2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * Bacula Director Job processing routines
24 * Kern Sibbald, October MM
31 /* Forward referenced subroutines */
32 static void *job_thread(void *arg);
33 static void job_monitor_watchdog(watchdog_t *self);
34 static void job_monitor_destructor(watchdog_t *self);
35 static bool job_check_maxwaittime(JCR *jcr);
36 static bool job_check_maxruntime(JCR *jcr);
37 static bool job_check_maxrunschedtime(JCR *jcr);
39 /* Imported subroutines */
40 extern void term_scheduler();
41 extern void term_ua_server();
43 /* Imported variables */
47 void init_job_server(int max_workers)
52 if ((stat = jobq_init(&job_queue, max_workers, job_thread)) != 0) {
54 Emsg1(M_ABORT, 0, _("Could not init job queue: ERR=%s\n"), be.bstrerror(stat));
57 wd->callback = job_monitor_watchdog;
58 wd->destructor = job_monitor_destructor;
61 wd->data = new_control_jcr("*JobMonitor*", JT_SYSTEM);
62 register_watchdog(wd);
65 void term_job_server()
67 jobq_destroy(&job_queue); /* ignore any errors */
71 * Run a job -- typically called by the scheduler, but may also
72 * be called by the UA (Console program).
74 * Returns: 0 on failure
78 JobId_t run_job(JCR *jcr)
82 Dmsg0(200, "Add jrc to work queue\n");
83 /* Queue the job to be run */
84 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
86 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
94 bool setup_job(JCR *jcr)
100 init_msg(jcr, jcr->messages, job_code_callback_director);
102 /* Initialize termination condition variable */
103 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
105 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
109 jcr->term_wait_inited = true;
111 create_unique_job_name(jcr, jcr->job->name());
112 jcr->setJobStatus(JS_Created);
118 Dmsg0(100, "Open database\n");
119 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
120 jcr->catalog->db_user, jcr->catalog->db_password,
121 jcr->catalog->db_address, jcr->catalog->db_port,
122 jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
123 jcr->catalog->disable_batch_insert);
124 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
125 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
126 jcr->catalog->db_name);
128 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
129 db_close_database(jcr, jcr->db);
135 Dmsg0(150, "DB opened\n");
137 jcr->fname = get_pool_memory(PM_FNAME);
139 if (!jcr->pool_source) {
140 jcr->pool_source = get_pool_memory(PM_MESSAGE);
141 pm_strcpy(jcr->pool_source, _("unknown source"));
143 if (!jcr->next_pool_source) {
144 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
145 pm_strcpy(jcr->next_pool_source, _("unknown source"));
148 if (jcr->JobReads()) {
149 if (!jcr->rpool_source) {
150 jcr->rpool_source = get_pool_memory(PM_MESSAGE);
151 pm_strcpy(jcr->rpool_source, _("unknown source"));
158 init_jcr_job_record(jcr);
159 if (!get_or_create_client_record(jcr)) {
163 if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
164 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
167 jcr->JobId = jcr->jr.JobId;
168 Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
169 jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);
171 generate_daemon_event(jcr, "JobStart");
172 new_plugins(jcr); /* instantiate plugins for this jcr */
173 generate_plugin_event(jcr, bDirEventJobStart);
175 if (job_canceled(jcr)) {
179 if (jcr->JobReads() && !jcr->rstorage) {
180 if (jcr->job->storage) {
181 copy_rwstorage(jcr, jcr->job->storage, _("Job resource"));
183 copy_rwstorage(jcr, jcr->job->pool->storage, _("Pool resource"));
186 if (!jcr->JobReads()) {
191 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
192 * this allows us to setup a proper job start record for restarting
193 * in case of later errors.
195 switch (jcr->getJobType()) {
197 if (!do_backup_init(jcr)) {
198 backup_cleanup(jcr, JS_ErrorTerminated);
203 if (!do_verify_init(jcr)) {
204 verify_cleanup(jcr, JS_ErrorTerminated);
209 if (!do_restore_init(jcr)) {
210 restore_cleanup(jcr, JS_ErrorTerminated);
215 if (!do_admin_init(jcr)) {
216 admin_cleanup(jcr, JS_ErrorTerminated);
222 if (!do_mac_init(jcr)) {
223 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
228 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
229 jcr->setJobStatus(JS_ErrorTerminated);
233 generate_plugin_event(jcr, bDirEventJobInit);
242 * Setup a job for a resume command
244 static bool setup_resume_job(JCR *jcr, JOB_DBR *jr)
249 init_msg(jcr, jcr->messages);
251 /* Initialize termination condition variable */
252 if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
254 Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
258 jcr->term_wait_inited = true;
260 jcr->setJobStatus(JS_Created);
266 Dmsg0(100, "Open database\n");
267 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
268 jcr->catalog->db_user, jcr->catalog->db_password,
269 jcr->catalog->db_address, jcr->catalog->db_port,
270 jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
271 jcr->catalog->disable_batch_insert);
272 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
273 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
274 jcr->catalog->db_name);
276 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
277 db_close_database(jcr, jcr->db);
282 Dmsg0(100, "DB opened\n");
284 jcr->fname = get_pool_memory(PM_FNAME);
286 if (!jcr->pool_source) {
287 jcr->pool_source = get_pool_memory(PM_MESSAGE);
288 pm_strcpy(jcr->pool_source, _("unknown source"));
290 if (!jcr->next_pool_source) {
291 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
292 pm_strcpy(jcr->next_pool_source, _("unknown source"));
297 * Setup Job record. Make sure original job is Incomplete.
299 memcpy(&jcr->jr, jr, sizeof(JOB_DBR));
300 jcr->sched_time = jcr->jr.SchedTime;
301 jcr->start_time = jcr->jr.StartTime;
302 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
303 jcr->setJobType(jcr->jr.JobType);
304 jcr->setJobLevel(jcr->jr.JobLevel);
305 jcr->JobId = jcr->jr.JobId;
306 if (!get_or_create_client_record(jcr)) {
307 Dmsg0(100, "Could not create client record.\n");
311 Dmsg6(100, "Got job record JobId=%d Job=%s Name=%s Type=%c Level=%c Status=%c\n",
312 jcr->jr.JobId, jcr->jr.Job, jcr->jr.Name, jcr->jr.JobType, jcr->jr.JobLevel,
314 if (jcr->jr.JobStatus != JS_Incomplete) {
315 /* ***FIXME*** add error message */
316 Dmsg1(100, "Job is not an Incomplete: status=%c\n", jcr->jr.JobStatus);
319 bstrncpy(jcr->Job, jcr->jr.Job, sizeof(jcr->Job));
320 jcr->setJobType(jcr->jr.JobType);
321 jcr->setJobLevel(jcr->jr.JobLevel);
323 generate_daemon_event(jcr, "JobStart");
324 new_plugins(jcr); /* instantiate plugins for this jcr */
325 generate_plugin_event(jcr, bDirEventJobStart);
327 if (job_canceled(jcr)) {
328 Dmsg0(100, "Oops. Job canceled\n");
332 /* Re-run the old job */
333 jcr->rerunning = true;
336 * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
337 * this allows us to setup a proper job start record for restarting
338 * in case of later errors.
340 switch (jcr->getJobType()) {
342 if (!do_backup_init(jcr)) {
343 backup_cleanup(jcr, JS_ErrorTerminated);
348 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
349 jcr->setJobStatus(JS_ErrorTerminated);
353 generate_plugin_event(jcr, bDirEventJobInit);
361 JobId_t resume_job(JCR *jcr, JOB_DBR *jr)
364 if (setup_resume_job(jcr, jr)) {
365 Dmsg0(200, "Add jrc to work queue\n");
366 /* Queue the job to be run */
367 if ((stat = jobq_add(&job_queue, jcr)) != 0) {
369 Jmsg(jcr, M_FATAL, 0, _("Could not add job queue: ERR=%s\n"), be.bstrerror(stat));
379 void update_job_end(JCR *jcr, int TermCode)
381 dequeue_messages(jcr); /* display any queued messages */
382 jcr->setJobStatus(TermCode);
383 update_job_end_record(jcr);
387 * This is the engine called by jobq.c:jobq_add() when we were pulled
388 * from the work queue.
389 * At this point, we are running in our own thread and all
390 * necessary resources are allocated -- see jobq.c
392 static void *job_thread(void *arg)
394 JCR *jcr = (JCR *)arg;
396 pthread_detach(pthread_self());
399 Dmsg0(200, "=====Start Job=========\n");
400 jcr->setJobStatus(JS_Running); /* this will be set only if no error */
401 jcr->start_time = time(NULL); /* set the real start time */
402 jcr->jr.StartTime = jcr->start_time;
404 if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay <
405 (utime_t)(jcr->start_time - jcr->sched_time)) {
406 jcr->setJobStatus(JS_Canceled);
407 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
410 if (job_check_maxrunschedtime(jcr)) {
411 jcr->setJobStatus(JS_Canceled);
412 Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
415 /* TODO : check if it is used somewhere */
416 if (jcr->job->RunScripts == NULL) {
417 Dmsg0(200, "Warning, job->RunScripts is empty\n");
418 jcr->job->RunScripts = New(alist(10, not_owned_by_alist));
421 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
422 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
425 /* Run any script BeforeJob on dird */
426 run_scripts(jcr, jcr->job->RunScripts, "BeforeJob");
429 * We re-update the job start record so that the start
430 * time is set after the run before job. This avoids
431 * that any files created by the run before job will
432 * be saved twice. They will be backed up in the current
433 * job, but not in the next one unless they are changed.
434 * Without this, they will be backed up in this job and
435 * in the next job run because in that case, their date
436 * is after the start of this run.
438 jcr->start_time = time(NULL);
439 jcr->jr.StartTime = jcr->start_time;
440 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
441 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
443 generate_plugin_event(jcr, bDirEventJobRun);
445 switch (jcr->getJobType()) {
447 if (!job_canceled(jcr) && do_backup(jcr)) {
450 backup_cleanup(jcr, JS_ErrorTerminated);
454 if (!job_canceled(jcr) && do_verify(jcr)) {
457 verify_cleanup(jcr, JS_ErrorTerminated);
461 if (!job_canceled(jcr) && do_restore(jcr)) {
464 restore_cleanup(jcr, JS_ErrorTerminated);
468 if (!job_canceled(jcr) && do_admin(jcr)) {
471 admin_cleanup(jcr, JS_ErrorTerminated);
476 if (!job_canceled(jcr) && do_mac(jcr)) {
479 mac_cleanup(jcr, JS_ErrorTerminated, JS_ErrorTerminated);
483 Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
487 run_scripts(jcr, jcr->job->RunScripts, "AfterJob");
489 /* Send off any queued messages */
490 if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
491 dequeue_messages(jcr);
494 generate_daemon_event(jcr, "JobEnd");
495 generate_plugin_event(jcr, bDirEventJobEnd);
496 Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
501 void sd_msg_thread_send_signal(JCR *jcr, int sig)
504 if ( !jcr->sd_msg_thread_done
505 && jcr->SD_msg_chan_started
506 && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
508 Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
509 pthread_kill(jcr->SD_msg_chan, sig);
514 static bool cancel_file_daemon_job(UAContext *ua, const char *cmd, JCR *jcr)
519 Dmsg0(100, "No client to cancel\n");
522 old_client = ua->jcr->client;
523 ua->jcr->client = jcr->client;
524 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
525 ua->error_msg(_("Failed to connect to File daemon.\n"));
526 ua->jcr->client = old_client;
529 Dmsg3(10, "Connected to file daemon %s for cancel ua.jcr=%p jcr=%p\n",
530 ua->jcr->client->name(), ua->jcr, jcr);
531 BSOCK *fd = ua->jcr->file_bsock;
532 fd->fsend("%s Job=%s\n", cmd, jcr->Job);
533 while (fd->recv() >= 0) {
534 ua->send_msg("%s", fd->msg);
536 fd->signal(BNET_TERMINATE);
537 free_bsock(ua->jcr->file_bsock);
538 ua->jcr->client = old_client;
542 static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
544 if (jcr->store_bsock) {
546 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
548 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
553 store.store = jcr->rstore;
555 store.store = jcr->wstore;
557 set_wstorage(ua->jcr, &store);
560 if (!ua->jcr->wstore) {
561 ua->error_msg(_("Failed to select Storage daemon.\n"));
565 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
566 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
570 Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
571 ua->jcr->wstore->name(), ua->jcr, jcr);
573 BSOCK *sd = ua->jcr->store_bsock;
574 sd->fsend("%s Job=%s\n", cmd, jcr->Job);
575 while (sd->recv() >= 0) {
576 ua->send_msg("%s", sd->msg);
578 sd->signal(BNET_TERMINATE);
579 free_bsock(ua->jcr->store_bsock);
583 /* The FD is not connected, so we try to complete JCR fields and send
584 * the cancel command.
586 static int cancel_inactive_job(UAContext *ua, JCR *jcr)
594 Dmsg2(10, "cancel_inactive_job ua.jcr=%p jcr=%p\n", ua->jcr, jcr);
597 memset(&cr, 0, sizeof(cr));
599 /* User is kind enough to provide the client name */
600 if ((i = find_arg_with_value(ua, "client")) > 0) {
601 bstrncpy(cr.Name, ua->argv[i], sizeof(cr.Name));
603 memset(&jr, 0, sizeof(jr));
604 bstrncpy(jr.Job, jcr->Job, sizeof(jr.Job));
606 if (!open_client_db(ua)) {
609 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
612 cr.ClientId = jr.ClientId;
613 if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
618 if (acl_access_ok(ua, Client_ACL, cr.Name)) {
619 client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
621 jcr->client = client;
623 Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
631 cancel_file_daemon_job(ua, "cancel", jcr);
633 /* At this time, we can't really guess the storage name from
636 store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
641 set_wstorage(ua->jcr, &store);
643 cancel_sd_job(ua, "cancel", jcr);
650 * Cancel a job -- typically called by the UA (Console program), but may also
651 * be called by the job watchdog.
653 * Returns: true if cancel appears to be successful
654 * false on failure. Message sent to ua->jcr.
657 cancel_job(UAContext *ua, JCR *jcr, bool cancel)
660 int32_t old_status = jcr->JobStatus;
662 const char *reason, *cmd;
663 bool force = find_arg(ua, "inactive") > 0;
665 Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
667 /* If the user explicitely ask, we can send the cancel command to
670 if (cancel && force) {
671 return cancel_inactive_job(ua, jcr);
675 status = JS_Canceled;
676 reason = _("canceled");
679 status = JS_Incomplete;
680 reason = _("stopped");
682 jcr->RescheduleIncompleteJobs = false; /* do not restart */
685 jcr->setJobStatus(status);
687 switch (old_status) {
690 case JS_WaitClientRes:
691 case JS_WaitStoreRes:
692 case JS_WaitPriority:
694 case JS_WaitStartTime:
696 ua->info_msg(_("JobId %s, Job %s marked to be %s.\n"),
697 edit_uint64(jcr->JobId, ed1), jcr->Job,
699 jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */
704 /* Cancel File daemon */
705 if (jcr->file_bsock) {
706 /* do not return now, we want to try to cancel the sd */
707 cancel_file_daemon_job(ua, cmd, jcr);
710 /* We test file_bsock because the previous operation can take
713 if (jcr->file_bsock && cancel) {
714 jcr->file_bsock->set_terminated();
715 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
718 /* Cancel Storage daemon */
719 if (jcr->store_bsock) {
720 /* do not return now, we want to try to cancel the sd socket */
721 cancel_sd_job(ua, cmd, jcr);
724 /* We test file_bsock because the previous operation can take
727 if (jcr->store_bsock && cancel) {
728 jcr->store_bsock->set_timed_out();
729 jcr->store_bsock->set_terminated();
730 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
731 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
734 /* Cancel Copy/Migration Storage daemon */
736 /* The wjcr is valid until we call free_jcr(jcr) */
737 JCR *wjcr = jcr->wjcr;
739 if (wjcr->store_bsock) {
740 /* do not return now, we want to try to cancel the sd socket */
741 cancel_sd_job(ua, cmd, wjcr);
743 /* We test file_bsock because the previous operation can take
746 if (wjcr->store_bsock && cancel) {
747 wjcr->store_bsock->set_timed_out();
748 wjcr->store_bsock->set_terminated();
749 sd_msg_thread_send_signal(wjcr, TIMEOUT_SIGNAL);
750 wjcr->my_thread_send_signal(TIMEOUT_SIGNAL);
759 void cancel_storage_daemon_job(JCR *jcr)
761 if (jcr->sd_canceled) {
762 return; /* cancel only once */
765 UAContext *ua = new_ua_context(jcr);
766 JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM);
769 ua->jcr = control_jcr;
770 if (jcr->store_bsock) {
771 if (!ua->jcr->wstorage) {
773 copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
775 copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
780 store.store = jcr->rstore;
782 store.store = jcr->wstore;
784 set_wstorage(ua->jcr, &store);
787 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
790 Dmsg0(200, "Connected to storage daemon\n");
791 sd = ua->jcr->store_bsock;
792 sd->fsend("cancel Job=%s\n", jcr->Job);
793 while (sd->recv() >= 0) {
795 sd->signal(BNET_TERMINATE);
796 free_bsock(ua->jcr->store_bsock);
797 jcr->sd_canceled = true;
798 jcr->store_bsock->set_timed_out();
799 jcr->store_bsock->set_terminated();
800 sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL);
801 jcr->my_thread_send_signal(TIMEOUT_SIGNAL);
804 free_jcr(control_jcr);
808 static void job_monitor_destructor(watchdog_t *self)
810 JCR *control_jcr = (JCR *)self->data;
812 free_jcr(control_jcr);
815 static void job_monitor_watchdog(watchdog_t *self)
817 JCR *control_jcr, *jcr;
819 control_jcr = (JCR *)self->data;
822 Dmsg1(800, "job_monitor_watchdog %p called\n", self);
827 if (jcr->JobId == 0 || job_canceled(jcr) || jcr->no_maxtime) {
828 Dmsg2(800, "Skipping JCR=%p Job=%s\n", jcr, jcr->Job);
832 /* check MaxWaitTime */
833 if (job_check_maxwaittime(jcr)) {
834 jcr->setJobStatus(JS_Canceled);
835 Qmsg(jcr, M_FATAL, 0, _("Max wait time exceeded. Job canceled.\n"));
837 /* check MaxRunTime */
838 } else if (job_check_maxruntime(jcr)) {
839 jcr->setJobStatus(JS_Canceled);
840 Qmsg(jcr, M_FATAL, 0, _("Max run time exceeded. Job canceled.\n"));
842 /* check MaxRunSchedTime */
843 } else if (job_check_maxrunschedtime(jcr)) {
844 jcr->setJobStatus(JS_Canceled);
845 Qmsg(jcr, M_FATAL, 0, _("Max run sched time exceeded. Job canceled.\n"));
850 Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
851 UAContext *ua = new_ua_context(jcr);
852 ua->jcr = control_jcr;
855 Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
859 /* Keep reference counts correct */
864 * Check if the maxwaittime has expired and it is possible
867 static bool job_check_maxwaittime(JCR *jcr)
873 if (!job_waiting(jcr)) {
877 if (jcr->wait_time) {
878 current = watchdog_time - jcr->wait_time;
881 Dmsg2(200, "check maxwaittime %u >= %u\n",
882 current + jcr->wait_time_sum, job->MaxWaitTime);
883 if (job->MaxWaitTime != 0 &&
884 (current + jcr->wait_time_sum) >= job->MaxWaitTime) {
892 * Check if maxruntime has expired and if the job can be
895 static bool job_check_maxruntime(JCR *jcr)
901 if (job_canceled(jcr) || !jcr->job_started) {
904 if (jcr->job->MaxRunTime == 0 && job->FullMaxRunTime == 0 &&
905 job->IncMaxRunTime == 0 && job->DiffMaxRunTime == 0) {
908 run_time = watchdog_time - jcr->start_time;
909 Dmsg7(200, "check_maxruntime %llu-%u=%llu >= %llu|%llu|%llu|%llu\n",
910 watchdog_time, jcr->start_time, run_time, job->MaxRunTime, job->FullMaxRunTime,
911 job->IncMaxRunTime, job->DiffMaxRunTime);
913 if (jcr->getJobLevel() == L_FULL && job->FullMaxRunTime != 0 &&
914 run_time >= job->FullMaxRunTime) {
915 Dmsg0(200, "check_maxwaittime: FullMaxcancel\n");
917 } else if (jcr->getJobLevel() == L_DIFFERENTIAL && job->DiffMaxRunTime != 0 &&
918 run_time >= job->DiffMaxRunTime) {
919 Dmsg0(200, "check_maxwaittime: DiffMaxcancel\n");
921 } else if (jcr->getJobLevel() == L_INCREMENTAL && job->IncMaxRunTime != 0 &&
922 run_time >= job->IncMaxRunTime) {
923 Dmsg0(200, "check_maxwaittime: IncMaxcancel\n");
925 } else if (job->MaxRunTime > 0 && run_time >= job->MaxRunTime) {
926 Dmsg0(200, "check_maxwaittime: Maxcancel\n");
934 * Check if MaxRunSchedTime has expired and if the job can be
937 static bool job_check_maxrunschedtime(JCR *jcr)
939 if (jcr->MaxRunSchedTime == 0 || job_canceled(jcr)) {
942 if ((watchdog_time - jcr->initial_sched_time) < jcr->MaxRunSchedTime) {
943 Dmsg3(200, "Job %p (%s) with MaxRunSchedTime %d not expired\n",
944 jcr, jcr->Job, jcr->MaxRunSchedTime);
952 * Get or create a Pool record with the given name.
953 * Returns: 0 on error
956 DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name)
960 memset(&pr, 0, sizeof(pr));
961 bstrncpy(pr.Name, pool_name, sizeof(pr.Name));
962 Dmsg1(110, "get_or_create_pool=%s\n", pool_name);
964 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
965 /* Try to create the pool */
966 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
967 Jmsg(jcr, M_FATAL, 0, _("Cannot create pool \"%s\" in database. ERR=%s"), pr.Name,
968 db_strerror(jcr->db));
971 Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name);
978 * Check for duplicate jobs.
979 * Returns: true if current job should continue
980 * false if current job should terminate
982 bool allow_duplicate_job(JCR *jcr)
985 JCR *djcr; /* possible duplicate job */
987 /* Is AllowDuplicateJobs is set or is duplicate checking
988 * disabled for this job? */
989 if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
992 Dmsg0(800, "Enter allow_duplicate_job\n");
994 * After this point, we do not want to allow any duplicate
999 if (jcr == djcr || djcr->JobId == 0) {
1000 continue; /* do not cancel this job or consoles */
1002 /* Does Job has the IgnoreDuplicateJobChecking flag set,
1003 * if so do not check it against other jobs */
1004 if (djcr->IgnoreDuplicateJobChecking) {
1007 if (strcmp(job->name(), djcr->job->name()) == 0) {
1008 bool cancel_dup = false;
1009 bool cancel_me = false;
1010 if (job->DuplicateJobProximity > 0) {
1011 utime_t now = (utime_t)time(NULL);
1012 if ((now - djcr->start_time) > job->DuplicateJobProximity) {
1013 continue; /* not really a duplicate */
1016 if (job->CancelLowerLevelDuplicates &&
1017 djcr->getJobType() == 'B' && jcr->getJobType() == 'B') {
1018 switch (jcr->getJobLevel()) {
1020 if (djcr->getJobLevel() == L_DIFFERENTIAL ||
1021 djcr->getJobLevel() == L_INCREMENTAL) {
1025 case L_DIFFERENTIAL:
1026 if (djcr->getJobLevel() == L_INCREMENTAL) {
1029 if (djcr->getJobLevel() == L_FULL) {
1034 if (djcr->getJobLevel() == L_FULL ||
1035 djcr->getJobLevel() == L_DIFFERENTIAL) {
1040 * cancel_dup will be done below
1043 /* Zap current job */
1044 jcr->setJobStatus(JS_Canceled);
1045 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1047 break; /* get out of foreach_jcr */
1050 /* Cancel one of the two jobs (me or dup) */
1051 /* If CancelQueuedDuplicates is set do so only if job is queued */
1052 if (job->CancelQueuedDuplicates) {
1053 switch (djcr->JobStatus) {
1056 case JS_WaitClientRes:
1057 case JS_WaitStoreRes:
1058 case JS_WaitPriority:
1059 case JS_WaitMaxJobs:
1060 case JS_WaitStartTime:
1062 cancel_dup = true; /* cancel queued duplicate */
1068 if (cancel_dup || job->CancelRunningDuplicates) {
1069 /* Zap the duplicated job djcr */
1070 UAContext *ua = new_ua_context(jcr);
1071 Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
1072 cancel_job(ua, djcr);
1073 bmicrosleep(0, 500000);
1074 djcr->setJobStatus(JS_Canceled);
1075 cancel_job(ua, djcr);
1076 free_ua_context(ua);
1077 Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
1079 /* Zap current job */
1080 jcr->setJobStatus(JS_Canceled);
1081 Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"),
1083 Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId);
1085 Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n",
1086 jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count());
1087 break; /* did our work, get out of foreach loop */
1096 * Apply pool overrides to get the storage properly setup.
1098 bool apply_wstorage_overrides(JCR *jcr, POOL *opool)
1102 Dmsg1(100, "Original pool=%s\n", opool->name());
1103 if (jcr->cmdline_next_pool_override) {
1104 /* Can be Command line or User input */
1105 source = NPRT(jcr->next_pool_source);
1106 } else if (jcr->run_next_pool_override) {
1107 pm_strcpy(jcr->next_pool_source, _("Run NextPool override"));
1108 pm_strcpy(jcr->pool_source, _("Run NextPool override"));
1109 source = _("Run NextPool override");
1110 } else if (jcr->job->next_pool) {
1111 /* Use Job Next Pool */
1112 jcr->next_pool = jcr->job->next_pool;
1113 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1114 pm_strcpy(jcr->pool_source, _("Job's NextPool resource"));
1115 source = _("Job's NextPool resource");
1117 /* Default to original pool->NextPool */
1118 jcr->next_pool = opool->NextPool;
1119 Dmsg1(100, "next_pool=%p\n", jcr->next_pool);
1120 if (jcr->next_pool) {
1121 Dmsg1(100, "Original pool next Pool = %s\n", NPRT(jcr->next_pool->name()));
1123 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1124 pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
1125 source = _("Pool's NextPool resource");
1129 * If the original backup pool has a NextPool, make sure a
1130 * record exists in the database.
1132 if (jcr->next_pool) {
1133 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->next_pool->name());
1134 if (jcr->jr.PoolId == 0) {
1139 if (!set_mac_wstorage(NULL, jcr, jcr->pool, jcr->next_pool, source)) {
1143 /* Set write pool and source. Not read pool is in rpool. */
1144 jcr->pool = jcr->next_pool;
1145 pm_strcpy(jcr->pool_source, source);
1151 void apply_pool_overrides(JCR *jcr)
1153 bool pool_override = false;
1155 if (jcr->run_pool_override) {
1156 pm_strcpy(jcr->pool_source, _("Run Pool override"));
1159 * Apply any level related Pool selections
1161 switch (jcr->getJobLevel()) {
1163 if (jcr->full_pool) {
1164 jcr->pool = jcr->full_pool;
1165 pool_override = true;
1166 if (jcr->run_full_pool_override) {
1167 pm_strcpy(jcr->pool_source, _("Run FullPool override"));
1169 pm_strcpy(jcr->pool_source, _("Job FullPool override"));
1174 if (jcr->inc_pool) {
1175 jcr->pool = jcr->inc_pool;
1176 pool_override = true;
1177 if (jcr->run_inc_pool_override) {
1178 pm_strcpy(jcr->pool_source, _("Run IncPool override"));
1180 pm_strcpy(jcr->pool_source, _("Job IncPool override"));
1184 case L_DIFFERENTIAL:
1185 if (jcr->diff_pool) {
1186 jcr->pool = jcr->diff_pool;
1187 pool_override = true;
1188 if (jcr->run_diff_pool_override) {
1189 pm_strcpy(jcr->pool_source, _("Run DiffPool override"));
1191 pm_strcpy(jcr->pool_source, _("Job DiffPool override"));
1196 /* Update catalog if pool overridden */
1197 if (pool_override && jcr->pool->catalog) {
1198 jcr->catalog = jcr->pool->catalog;
1199 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1205 * Get or create a Client record for this Job
1207 bool get_or_create_client_record(JCR *jcr)
1212 Jmsg(jcr, M_FATAL, 0, _("No Client specified.\n"));
1215 memset(&cr, 0, sizeof(cr));
1216 bstrncpy(cr.Name, jcr->client->hdr.name, sizeof(cr.Name));
1217 cr.AutoPrune = jcr->client->AutoPrune;
1218 cr.FileRetention = jcr->client->FileRetention;
1219 cr.JobRetention = jcr->client->JobRetention;
1220 if (!jcr->client_name) {
1221 jcr->client_name = get_pool_memory(PM_NAME);
1223 pm_strcpy(jcr->client_name, jcr->client->hdr.name);
1224 if (!db_create_client_record(jcr, jcr->db, &cr)) {
1225 Jmsg(jcr, M_FATAL, 0, _("Could not create Client record. ERR=%s\n"),
1226 db_strerror(jcr->db));
1229 jcr->jr.ClientId = cr.ClientId;
1231 if (!jcr->client_uname) {
1232 jcr->client_uname = get_pool_memory(PM_NAME);
1234 pm_strcpy(jcr->client_uname, cr.Uname);
1236 Dmsg2(100, "Created Client %s record %d\n", jcr->client->hdr.name,
1242 * Get or Create FileSet record
1244 bool get_or_create_fileset_record(JCR *jcr)
1248 memset(&fsr, 0, sizeof(FILESET_DBR));
1249 bstrncpy(fsr.FileSet, jcr->fileset->hdr.name, sizeof(fsr.FileSet));
1250 if (jcr->fileset->have_MD5) {
1251 struct MD5Context md5c;
1252 unsigned char digest[MD5HashSize];
1253 memcpy(&md5c, &jcr->fileset->md5c, sizeof(md5c));
1254 MD5Final(digest, &md5c);
1256 * Keep the flag (last arg) set to false otherwise old FileSets will
1257 * get new MD5 sums and the user will get Full backups on everything
1259 bin_to_base64(fsr.MD5, sizeof(fsr.MD5), (char *)digest, MD5HashSize, false);
1260 bstrncpy(jcr->fileset->MD5, fsr.MD5, sizeof(jcr->fileset->MD5));
1262 Jmsg(jcr, M_WARNING, 0, _("FileSet MD5 digest not found.\n"));
1264 if (!jcr->fileset->ignore_fs_changes ||
1265 !db_get_fileset_record(jcr, jcr->db, &fsr)) {
1266 if (!db_create_fileset_record(jcr, jcr->db, &fsr)) {
1267 Jmsg(jcr, M_ERROR, 0, _("Could not create FileSet \"%s\" record. ERR=%s\n"),
1268 fsr.FileSet, db_strerror(jcr->db));
1272 jcr->jr.FileSetId = fsr.FileSetId;
1273 bstrncpy(jcr->FSCreateTime, fsr.cCreateTime, sizeof(jcr->FSCreateTime));
1274 Dmsg2(119, "Created FileSet %s record %u\n", jcr->fileset->hdr.name,
1279 void init_jcr_job_record(JCR *jcr)
1281 jcr->jr.SchedTime = jcr->sched_time;
1282 jcr->jr.StartTime = jcr->start_time;
1283 jcr->jr.EndTime = 0; /* perhaps rescheduled, clear it */
1284 jcr->jr.JobType = jcr->getJobType();
1285 jcr->jr.JobLevel = jcr->getJobLevel();
1286 jcr->jr.JobStatus = jcr->JobStatus;
1287 jcr->jr.JobId = jcr->JobId;
1288 bstrncpy(jcr->jr.Name, jcr->job->name(), sizeof(jcr->jr.Name));
1289 bstrncpy(jcr->jr.Job, jcr->Job, sizeof(jcr->jr.Job));
1293 * Write status and such in DB
1295 void update_job_end_record(JCR *jcr)
1297 jcr->jr.EndTime = time(NULL);
1298 jcr->end_time = jcr->jr.EndTime;
1299 jcr->jr.JobId = jcr->JobId;
1300 jcr->jr.JobStatus = jcr->JobStatus;
1301 jcr->jr.JobFiles = jcr->JobFiles;
1302 jcr->jr.JobBytes = jcr->JobBytes;
1303 jcr->jr.ReadBytes = jcr->ReadBytes;
1304 jcr->jr.VolSessionId = jcr->VolSessionId;
1305 jcr->jr.VolSessionTime = jcr->VolSessionTime;
1306 jcr->jr.JobErrors = jcr->JobErrors;
1307 jcr->jr.HasBase = jcr->HasBase;
1308 if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
1309 Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
1310 db_strerror(jcr->db));
1315 * Takes base_name and appends (unique) current
1316 * date and time to form unique job name.
1318 * Note, the seconds are actually a sequence number. This
1319 * permits us to start a maximum fo 59 unique jobs a second, which
1320 * should be sufficient.
1322 * Returns: unique job name in jcr->Job
1323 * date/time in jcr->start_time
1325 void create_unique_job_name(JCR *jcr, const char *base_name)
1327 /* Job start mutex */
1328 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
1329 static time_t last_start_time = 0;
1331 time_t now = time(NULL);
1333 char dt[MAX_TIME_LENGTH];
1334 char name[MAX_NAME_LENGTH];
1339 /* Guarantee unique start time -- maximum one per second, and
1340 * thus unique Job Name
1342 P(mutex); /* lock creation of jobs */
1344 if (seq > 59) { /* wrap as if it is seconds */
1346 while (now == last_start_time) {
1347 bmicrosleep(0, 500000);
1351 last_start_time = now;
1353 V(mutex); /* allow creation of jobs */
1354 jcr->start_time = now;
1355 /* Form Unique JobName */
1356 (void)localtime_r(&now, &tm);
1357 /* Use only characters that are permitted in Windows filenames */
1358 strftime(dt, sizeof(dt), "%Y-%m-%d_%H.%M.%S", &tm);
1359 len = strlen(dt) + 5; /* dt + .%02d EOS */
1360 bstrncpy(name, base_name, sizeof(name));
1361 name[sizeof(name)-len] = 0; /* truncate if too long */
1362 bsnprintf(jcr->Job, sizeof(jcr->Job), "%s.%s_%02d", name, dt, local_seq); /* add date & time */
1363 /* Convert spaces into underscores */
1364 for (p=jcr->Job; *p; p++) {
1369 Dmsg2(100, "JobId=%u created Job=%s\n", jcr->JobId, jcr->Job);
1372 /* Called directly from job rescheduling */
1373 void dird_free_jcr_pointers(JCR *jcr)
1375 /* Close but do not free bsock packets */
1376 if (jcr->file_bsock) {
1377 Dmsg0(200, "Close File bsock\n");
1378 jcr->file_bsock->close();
1380 if (jcr->store_bsock) {
1381 Dmsg0(200, "Close Store bsock\n");
1382 jcr->store_bsock->close();
1385 bfree_and_null(jcr->sd_auth_key);
1386 bfree_and_null(jcr->where);
1387 bfree_and_null(jcr->RestoreBootstrap);
1388 jcr->cached_attribute = false;
1389 bfree_and_null(jcr->ar);
1391 free_and_null_pool_memory(jcr->JobIds);
1392 free_and_null_pool_memory(jcr->client_uname);
1393 free_and_null_pool_memory(jcr->attr);
1394 free_and_null_pool_memory(jcr->fname);
1395 free_and_null_pool_memory(jcr->media_type);
1399 * Free the Job Control Record if no one is still using it.
1400 * Called from main free_jcr() routine in src/lib/jcr.c so
1401 * that we can do our Director specific cleanup of the jcr.
1403 void dird_free_jcr(JCR *jcr)
1405 Dmsg0(200, "Start dird free_jcr\n");
1407 dird_free_jcr_pointers(jcr);
1409 free_jcr(jcr->wjcr);
1412 /* Free bsock packets */
1413 free_bsock(jcr->file_bsock);
1414 free_bsock(jcr->store_bsock);
1415 if (jcr->term_wait_inited) {
1416 pthread_cond_destroy(&jcr->term_wait);
1417 jcr->term_wait_inited = false;
1419 if (jcr->db_batch) {
1420 db_close_database(jcr, jcr->db_batch);
1421 jcr->db_batch = NULL;
1422 jcr->batch_started = false;
1425 db_close_database(jcr, jcr->db);
1429 free_and_null_pool_memory(jcr->stime);
1430 free_and_null_pool_memory(jcr->fname);
1431 free_and_null_pool_memory(jcr->pool_source);
1432 free_and_null_pool_memory(jcr->next_pool_source);
1433 free_and_null_pool_memory(jcr->catalog_source);
1434 free_and_null_pool_memory(jcr->rpool_source);
1435 free_and_null_pool_memory(jcr->wstore_source);
1436 free_and_null_pool_memory(jcr->rstore_source);
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);
1501 jcr->fname = get_pool_memory(PM_FNAME);
1503 if (!jcr->pool_source) {
1504 jcr->pool_source = get_pool_memory(PM_MESSAGE);
1506 if (!jcr->next_pool_source) {
1507 jcr->next_pool_source = get_pool_memory(PM_MESSAGE);
1509 if (!jcr->catalog_source) {
1510 jcr->catalog_source = get_pool_memory(PM_MESSAGE);
1513 jcr->JobPriority = job->Priority;
1514 /* Copy storage definitions -- deleted in dir_free_jcr above */
1516 copy_rwstorage(jcr, job->storage, _("Job resource"));
1518 copy_rwstorage(jcr, job->pool->storage, _("Pool resource"));
1520 jcr->client = job->client;
1521 ASSERT2(jcr->client, "jcr->client==NULL!!!");
1522 if (!jcr->client_name) {
1523 jcr->client_name = get_pool_memory(PM_NAME);
1525 pm_strcpy(jcr->client_name, jcr->client->name());
1526 jcr->pool = job->pool;
1527 pm_strcpy(jcr->pool_source, _("Job resource"));
1528 if (job->next_pool) {
1529 /* Use Job's Next Pool */
1530 jcr->next_pool = job->next_pool;
1531 pm_strcpy(jcr->next_pool_source, _("Job's NextPool resource"));
1533 /* Default to original pool->NextPool */
1534 jcr->next_pool = job->pool->NextPool;
1535 pm_strcpy(jcr->next_pool_source, _("Job Pool's NextPool resource"));
1537 jcr->full_pool = job->full_pool;
1538 jcr->inc_pool = job->inc_pool;
1539 jcr->diff_pool = job->diff_pool;
1540 if (job->pool->catalog) {
1541 jcr->catalog = job->pool->catalog;
1542 pm_strcpy(jcr->catalog_source, _("Pool resource"));
1544 jcr->catalog = job->client->catalog;
1545 pm_strcpy(jcr->catalog_source, _("Client resource"));
1547 jcr->fileset = job->fileset;
1548 jcr->accurate = job->accurate;
1549 jcr->messages = job->messages;
1550 jcr->spool_data = job->spool_data;
1551 jcr->spool_size = job->spool_size;
1552 jcr->write_part_after_job = job->write_part_after_job;
1553 jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
1554 jcr->MaxRunSchedTime = job->MaxRunSchedTime;
1555 if (jcr->RestoreBootstrap) {
1556 free(jcr->RestoreBootstrap);
1557 jcr->RestoreBootstrap = NULL;
1559 /* This can be overridden by Console program */
1560 if (job->RestoreBootstrap) {
1561 jcr->RestoreBootstrap = bstrdup(job->RestoreBootstrap);
1563 /* This can be overridden by Console program */
1564 jcr->verify_job = job->verify_job;
1565 /* If no default level given, set one */
1566 if (jcr->getJobLevel() == 0) {
1567 switch (jcr->getJobType()) {
1569 jcr->setJobLevel(L_VERIFY_CATALOG);
1572 jcr->setJobLevel(L_INCREMENTAL);
1576 jcr->setJobLevel(L_NONE);
1579 jcr->setJobLevel(L_FULL);
1586 * Copy the storage definitions from an alist to the JCR
1588 void copy_rwstorage(JCR *jcr, alist *storage, const char *where)
1590 if (jcr->JobReads()) {
1591 copy_rstorage(jcr, storage, where);
1593 copy_wstorage(jcr, storage, where);
1597 /* Set storage override. Releases any previous storage definition */
1598 void set_rwstorage(JCR *jcr, USTORE *store)
1601 Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n"));
1604 if (jcr->JobReads()) {
1605 set_rstorage(jcr, store);
1607 set_wstorage(jcr, store);
1610 void free_rwstorage(JCR *jcr)
1617 * Copy the storage definitions from an alist to the JCR
1619 void copy_rstorage(JCR *jcr, alist *storage, const char *where)
1623 if (jcr->rstorage) {
1624 delete jcr->rstorage;
1626 jcr->rstorage = New(alist(10, not_owned_by_alist));
1627 foreach_alist(st, storage) {
1628 jcr->rstorage->append(st);
1630 if (!jcr->rstore_source) {
1631 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1633 pm_strcpy(jcr->rstore_source, where);
1634 if (jcr->rstorage) {
1635 jcr->rstore = (STORE *)jcr->rstorage->first();
1641 /* Set storage override. Remove all previous storage */
1642 void set_rstorage(JCR *jcr, USTORE *store)
1646 if (!store->store) {
1649 if (jcr->rstorage) {
1652 if (!jcr->rstorage) {
1653 jcr->rstorage = New(alist(10, not_owned_by_alist));
1655 jcr->rstore = store->store;
1656 if (!jcr->rstore_source) {
1657 jcr->rstore_source = get_pool_memory(PM_MESSAGE);
1659 pm_strcpy(jcr->rstore_source, store->store_source);
1660 foreach_alist(storage, jcr->rstorage) {
1661 if (store->store == storage) {
1665 /* Store not in list, so add it */
1666 jcr->rstorage->prepend(store->store);
1669 void free_rstorage(JCR *jcr)
1671 if (jcr->rstorage) {
1672 delete jcr->rstorage;
1673 jcr->rstorage = NULL;
1679 * Copy the storage definitions from an alist to the JCR
1681 void copy_wstorage(JCR *jcr, alist *storage, const char *where)
1685 if (jcr->wstorage) {
1686 delete jcr->wstorage;
1688 jcr->wstorage = New(alist(10, not_owned_by_alist));
1689 foreach_alist(st, storage) {
1690 Dmsg1(100, "wstorage=%s\n", st->name());
1691 jcr->wstorage->append(st);
1693 if (!jcr->wstore_source) {
1694 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1696 pm_strcpy(jcr->wstore_source, where);
1697 if (jcr->wstorage) {
1698 jcr->wstore = (STORE *)jcr->wstorage->first();
1699 Dmsg2(100, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1705 /* Set storage override. Remove all previous storage */
1706 void set_wstorage(JCR *jcr, USTORE *store)
1710 if (!store->store) {
1713 if (jcr->wstorage) {
1716 if (!jcr->wstorage) {
1717 jcr->wstorage = New(alist(10, not_owned_by_alist));
1719 jcr->wstore = store->store;
1720 if (!jcr->wstore_source) {
1721 jcr->wstore_source = get_pool_memory(PM_MESSAGE);
1723 pm_strcpy(jcr->wstore_source, store->store_source);
1724 Dmsg2(50, "wstore=%s where=%s\n", jcr->wstore->name(), jcr->wstore_source);
1725 foreach_alist(storage, jcr->wstorage) {
1726 if (store->store == storage) {
1730 /* Store not in list, so add it */
1731 jcr->wstorage->prepend(store->store);
1734 void free_wstorage(JCR *jcr)
1736 if (jcr->wstorage) {
1737 delete jcr->wstorage;
1738 jcr->wstorage = NULL;
1743 void create_clones(JCR *jcr)
1746 * Fire off any clone jobs (run directives)
1748 Dmsg2(900, "cloned=%d run_cmds=%p\n", jcr->cloned, jcr->job->run_cmds);
1749 if (!jcr->cloned && jcr->job->run_cmds) {
1751 JOB *job = jcr->job;
1752 POOLMEM *cmd = get_pool_memory(PM_FNAME);
1753 UAContext *ua = new_ua_context(jcr);
1755 foreach_alist(runcmd, job->run_cmds) {
1756 cmd = edit_job_codes(jcr, cmd, runcmd, "", job_code_callback_director);
1757 Mmsg(ua->cmd, "run %s cloned=yes", cmd);
1758 Dmsg1(900, "=============== Clone cmd=%s\n", ua->cmd);
1759 parse_ua_args(ua); /* parse command */
1760 int stat = run_cmd(ua, ua->cmd);
1762 Jmsg(jcr, M_ERROR, 0, _("Could not start clone job: \"%s\".\n"),
1765 Jmsg(jcr, M_INFO, 0, _("Clone JobId %d started.\n"), stat);
1768 free_ua_context(ua);
1769 free_pool_memory(cmd);
1774 * Given: a JobId in jcr->previous_jr.JobId,
1775 * this subroutine writes a bsr file to restore that job.
1776 * Returns: -1 on error
1777 * number of files if OK
1779 int create_restore_bootstrap_file(JCR *jcr)
1785 memset(&rx, 0, sizeof(rx));
1787 rx.JobIds = (char *)"";
1788 rx.bsr->JobId = jcr->previous_jr.JobId;
1789 ua = new_ua_context(jcr);
1790 if (!complete_bsr(ua, rx.bsr)) {
1794 rx.bsr->fi = new_findex();
1795 rx.bsr->fi->findex = 1;
1796 rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
1797 jcr->ExpectedFiles = write_bsr_file(ua, rx);
1798 if (jcr->ExpectedFiles == 0) {
1802 free_ua_context(ua);
1804 jcr->needs_sd = true;
1805 return jcr->ExpectedFiles;
1808 free_ua_context(ua);
1813 /* TODO: redirect command ouput to job log */
1814 bool run_console_command(JCR *jcr, const char *cmd)
1818 JCR *ljcr = new_control_jcr("-RunScript-", JT_CONSOLE);
1819 ua = new_ua_context(ljcr);
1820 /* run from runscript and check if commands are authorized */
1821 ua->runscript = true;
1822 Mmsg(ua->cmd, "%s", cmd);
1823 Dmsg1(100, "Console command: %s\n", ua->cmd);
1825 if (ua->argc > 0 && ua->argk[0][0] == '.') {
1826 ok = do_a_dot_command(ua);
1828 ok = do_a_command(ua);
1830 free_ua_context(ua);