/*
Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2015 Kern Sibbald
- Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2017 Kern Sibbald
The original author of Bacula is Kern Sibbald, with contributions
from many others, a complete list can be found in the file AUTHORS.
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- This notice must be preserved when any source code is
+ This notice must be preserved when any source code is
conveyed and/or propagated.
Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
- *
* Bacula Director Job processing routines
*
* Kern Sibbald, October MM
- *
*/
#include "bacula.h"
jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
jcr->catalog->db_user, jcr->catalog->db_password,
jcr->catalog->db_address, jcr->catalog->db_port,
- jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
+ jcr->catalog->db_socket, jcr->catalog->db_ssl_mode,
+ jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert,
+ jcr->catalog->db_ssl_ca, jcr->catalog->db_ssl_capath,
+ jcr->catalog->db_ssl_cipher,
+ jcr->catalog->mult_db_connections,
jcr->catalog->disable_batch_insert);
if (!jcr->db || !db_open_database(jcr, jcr->db)) {
Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
jcr->catalog->db_user, jcr->catalog->db_password,
jcr->catalog->db_address, jcr->catalog->db_port,
- jcr->catalog->db_socket, jcr->catalog->mult_db_connections,
+ jcr->catalog->db_socket, jcr->catalog->db_ssl_mode,
+ jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert,
+ jcr->catalog->db_ssl_ca, jcr->catalog->db_ssl_capath,
+ jcr->catalog->db_ssl_cipher,
+ jcr->catalog->mult_db_connections,
jcr->catalog->disable_batch_insert);
if (!jcr->db || !db_open_database(jcr, jcr->db)) {
Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
/* The FD is not connected, so we try to complete JCR fields and send
* the cancel command.
*/
-static int cancel_inactive_job(UAContext *ua, JCR *jcr)
+int cancel_inactive_job(UAContext *ua)
{
CLIENT_DBR cr;
JOB_DBR jr;
int i;
USTORE store;
- CLIENT *client;
+ CLIENT *client;
+ JCR *jcr = new_jcr(sizeof(JCR), dird_free_jcr);
- Dmsg2(10, "cancel_inactive_job ua.jcr=%p jcr=%p\n", ua->jcr, jcr);
+ memset(&jr, 0, sizeof(jr));
+ memset(&cr, 0, sizeof(cr));
- if (!jcr->client) {
- memset(&cr, 0, sizeof(cr));
+ if ((i = find_arg_with_value(ua, "jobid")) > 0) {
+ jr.JobId = str_to_int64(ua->argv[i]);
- /* User is kind enough to provide the client name */
- if ((i = find_arg_with_value(ua, "client")) > 0) {
- bstrncpy(cr.Name, ua->argv[i], sizeof(cr.Name));
- } else {
- memset(&jr, 0, sizeof(jr));
- bstrncpy(jr.Job, jcr->Job, sizeof(jr.Job));
+ } else if ((i = find_arg_with_value(ua, "ujobid")) > 0) {
+ bstrncpy(jr.Job, ua->argv[i], sizeof(jr.Job));
- if (!open_client_db(ua)) {
- goto bail_out;
- }
- if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
- goto bail_out;
- }
- cr.ClientId = jr.ClientId;
- if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
- goto bail_out;
- }
- }
+ } else {
+ ua->error_msg(_("jobid/ujobid argument not found.\n"));
+ goto bail_out;
+ }
- if (acl_access_ok(ua, Client_ACL, cr.Name)) {
- client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
- if (client) {
- jcr->client = client;
- } else {
- Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
- goto bail_out;
- }
+ if (!open_client_db(ua)) {
+ goto bail_out;
+ }
+
+ if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
+ ua->error_msg(_("Job %ld/%s not found in database.\n"), jr.JobId, jr.Job);
+ goto bail_out;
+ }
+
+ if (!acl_access_ok(ua, Job_ACL, jr.Name)) {
+ ua->error_msg(_("Job %s is not accessible from this console\n"), jr.Name);
+ goto bail_out;
+ }
+
+ cr.ClientId = jr.ClientId;
+ if (!cr.ClientId || !db_get_client_record(ua->jcr, ua->db, &cr)) {
+ ua->error_msg(_("Client %ld not found in database.\n"), jr.ClientId);
+ goto bail_out;
+ }
+
+ if (acl_access_client_ok(ua, cr.Name, jr.JobType)) {
+ client = (CLIENT *)GetResWithName(R_CLIENT, cr.Name);
+ if (client) {
+ jcr->client = client;
} else {
+ Jmsg1(jcr, M_FATAL, 0, _("Client resource \"%s\" does not exist.\n"), cr.Name);
goto bail_out;
}
+ } else {
+ goto bail_out;
}
+ jcr->JobId = jr.JobId;
+ bstrncpy(jcr->Job, jr.Job, sizeof(jcr->Job));
+
cancel_file_daemon_job(ua, "cancel", jcr);
/* At this time, we can't really guess the storage name from
goto bail_out;
}
- set_wstorage(ua->jcr, &store);
-
+ set_wstorage(jcr, &store);
cancel_sd_job(ua, "cancel", jcr);
bail_out:
+ jcr->JobId = 0;
+ free_jcr(jcr);
return 1;
}
* false on failure. Message sent to ua->jcr.
*/
bool
-cancel_job(UAContext *ua, JCR *jcr, bool cancel)
+cancel_job(UAContext *ua, JCR *jcr, int wait, bool cancel)
{
char ed1[50];
int32_t old_status = jcr->JobStatus;
int status;
const char *reason, *cmd;
- bool force = find_arg(ua, "inactive") > 0;
Dmsg3(10, "cancel_job jcr=%p jobid=%d use_count\n", jcr, jcr->JobId, jcr->use_count());
- /* If the user explicitely ask, we can send the cancel command to
- * the FD.
- */
- if (cancel && force) {
- return cancel_inactive_job(ua, jcr);
- }
-
if (cancel) {
status = JS_Canceled;
reason = _("canceled");
/* Cancel File daemon */
if (jcr->file_bsock) {
+ btimer_t *tid;
/* do not return now, we want to try to cancel the sd */
+ tid = start_bsock_timer(jcr->file_bsock, 120);
cancel_file_daemon_job(ua, cmd, jcr);
+ stop_bsock_timer(tid);
}
/* We test file_bsock because the previous operation can take
/* Cancel Storage daemon */
if (jcr->store_bsock) {
+ btimer_t *tid;
/* do not return now, we want to try to cancel the sd socket */
+ tid = start_bsock_timer(jcr->store_bsock, 120);
cancel_sd_job(ua, cmd, jcr);
+ stop_bsock_timer(tid);
}
/* We test file_bsock because the previous operation can take
JCR *wjcr = jcr->wjcr;
if (wjcr->store_bsock) {
+ btimer_t *tid;
/* do not return now, we want to try to cancel the sd socket */
+ tid = start_bsock_timer(wjcr->store_bsock, 120);
cancel_sd_job(ua, cmd, wjcr);
+ stop_bsock_timer(tid);
}
- /* We test file_bsock because the previous operation can take
+ /* We test store_bsock because the previous operation can take
* several minutes
*/
if (wjcr->store_bsock && cancel) {
free_jcr(control_jcr);
}
-static void job_monitor_watchdog(watchdog_t *self)
+extern "C" void *cancel_thread(void *arg)
{
- JCR *control_jcr, *jcr;
+ JCR *jcr = (JCR *)arg;
+ UAContext *ua;
+ JCR *control_jcr;
- control_jcr = (JCR *)self->data;
+ pthread_detach(pthread_self());
+ ua = new_ua_context(jcr);
+ control_jcr = new_control_jcr("*CancelThread*", JT_SYSTEM);
+ ua->jcr = control_jcr;
+
+ Dmsg3(400, "Cancelling JCR %p JobId=%d (%s)\n", jcr, jcr->JobId, jcr->Job);
+ cancel_job(ua, jcr, 120);
+ Dmsg2(400, "Have cancelled JCR %p JobId=%d\n", jcr, jcr->JobId);
+
+ free_ua_context(ua);
+ free_jcr(control_jcr);
+ free_jcr(jcr);
+ return NULL;
+}
+
+static void job_monitor_watchdog(watchdog_t *wd)
+{
+ JCR *jcr;
Dsm_check(100);
- Dmsg1(800, "job_monitor_watchdog %p called\n", self);
+ Dmsg1(800, "job_monitor_watchdog %p called\n", wd);
foreach_jcr(jcr) {
bool cancel = false;
}
if (cancel) {
- Dmsg3(800, "Cancelling JCR %p jobid %d (%s)\n", jcr, jcr->JobId, jcr->Job);
- UAContext *ua = new_ua_context(jcr);
- ua->jcr = control_jcr;
- cancel_job(ua, jcr);
- free_ua_context(ua);
- Dmsg2(800, "Have cancelled JCR %p Job=%d\n", jcr, jcr->JobId);
+ pthread_t thid;
+ int status;
+ jcr->inc_use_count();
+ if ((status=pthread_create(&thid, NULL, cancel_thread, (void *)jcr)) != 0) {
+ berrno be;
+ Jmsg1(jcr, M_WARNING, 0, _("Cannot create cancel thread: ERR=%s\n"), be.bstrerror(status));
+ free_jcr(jcr);
+ }
}
-
}
/* Keep reference counts correct */
endeach_jcr(jcr);
JOB *job = jcr->job;
JCR *djcr; /* possible duplicate job */
- /* Is AllowDuplicateJobs is set or is duplicate checking
+ /* Is AllowDuplicateJobs is set or is duplicate checking
* disabled for this job? */
if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) {
return true;
*/
foreach_jcr(djcr) {
- if (jcr == djcr || djcr->JobId == 0) {
+ if (jcr == djcr || djcr->is_internal_job() || !djcr->job) {
continue; /* do not cancel this job or consoles */
}
/* Does Job has the IgnoreDuplicateJobChecking flag set,
* if so do not check it against other jobs */
if (djcr->IgnoreDuplicateJobChecking) {
- continue;
- }
- if (strcmp(job->name(), djcr->job->name()) == 0) {
+ continue;
+ }
+ if ((strcmp(job->name(), djcr->job->name()) == 0) &&
+ djcr->getJobType() == jcr->getJobType()) /* A duplicate is about the same name and the same type */
+ {
bool cancel_dup = false;
bool cancel_me = false;
if (job->DuplicateJobProximity > 0) {
djcr->JobId);
break; /* get out of foreach_jcr */
}
- }
+ }
/* Cancel one of the two jobs (me or dup) */
/* If CancelQueuedDuplicates is set do so only if job is queued */
if (job->CancelQueuedDuplicates) {
/* Zap the duplicated job djcr */
UAContext *ua = new_ua_context(jcr);
Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId);
- cancel_job(ua, djcr);
+ cancel_job(ua, djcr, 60);
bmicrosleep(0, 500000);
djcr->setJobStatus(JS_Canceled);
- cancel_job(ua, djcr);
+ cancel_job(ua, djcr, 60);
free_ua_context(ua);
Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId);
} else {
jcr->jr.ReadBytes = jcr->ReadBytes;
jcr->jr.VolSessionId = jcr->VolSessionId;
jcr->jr.VolSessionTime = jcr->VolSessionTime;
- jcr->jr.JobErrors = jcr->JobErrors;
+ jcr->jr.JobErrors = jcr->JobErrors + jcr->SDErrors;
jcr->jr.HasBase = jcr->HasBase;
if (!db_update_job_end_record(jcr, jcr->db, &jcr->jr)) {
Jmsg(jcr, M_WARNING, 0, _("Error updating job record. %s"),
free_and_null_pool_memory(jcr->rpool_source);
free_and_null_pool_memory(jcr->wstore_source);
free_and_null_pool_memory(jcr->rstore_source);
+ free_and_null_pool_memory(jcr->next_vol_list);
+ free_and_null_pool_memory(jcr->component_fname);
/* Delete lists setup to hold storage pointers */
free_rwstorage(jcr);
jcr->job_end_push.destroy();
- if (jcr->JobId != 0) {
+ if (jcr->JobId != 0)
write_state_file(director->working_directory, "bacula-dir", get_first_port_host_order(director->DIRaddrs));
- }
+ if (jcr->plugin_config) {
+ free_plugin_config_items(jcr->plugin_config);
+ delete jcr->plugin_config;
+ jcr->plugin_config = NULL;
+ }
free_plugins(jcr); /* release instantiated plugins */
+ garbage_collect_memory_pool();
+
Dmsg0(200, "End dird free_jcr\n");
}
jcr->setJobLevel(job->JobLevel);
break;
}
-
+ if (!jcr->next_vol_list) {
+ jcr->next_vol_list = get_pool_memory(PM_FNAME);
+ }
if (!jcr->fname) {
jcr->fname = get_pool_memory(PM_FNAME);
}
jcr->spool_data = job->spool_data;
jcr->spool_size = job->spool_size;
jcr->write_part_after_job = job->write_part_after_job;
- jcr->IgnoreDuplicateJobChecking = job->IgnoreDuplicateJobChecking;
jcr->MaxRunSchedTime = job->MaxRunSchedTime;
if (jcr->RestoreBootstrap) {
free(jcr->RestoreBootstrap);
}
/*
- * Given: a JobId in jcr->previous_jr.JobId,
+ * Given: a JobId and FileIndex
* this subroutine writes a bsr file to restore that job.
* Returns: -1 on error
* number of files if OK
*/
-int create_restore_bootstrap_file(JCR *jcr)
+int create_restore_bootstrap_file(JCR *jcr, JobId_t jobid, int findex1, int findex2)
{
RESTORE_CTX rx;
UAContext *ua;
int files;
memset(&rx, 0, sizeof(rx));
- rx.bsr = new_bsr();
rx.JobIds = (char *)"";
- rx.bsr->JobId = jcr->previous_jr.JobId;
+
+ rx.bsr_list = create_bsr_list(jobid, findex1, findex2);
+
ua = new_ua_context(jcr);
- if (!complete_bsr(ua, rx.bsr)) {
+ if (!complete_bsr(ua, rx.bsr_list)) {
files = -1;
goto bail_out;
}
- rx.bsr->fi = new_findex();
- rx.bsr->fi->findex = 1;
- rx.bsr->fi->findex2 = jcr->previous_jr.JobFiles;
+
jcr->ExpectedFiles = write_bsr_file(ua, rx);
if (jcr->ExpectedFiles == 0) {
files = 0;
goto bail_out;
}
free_ua_context(ua);
- free_bsr(rx.bsr);
+ free_bsr(rx.bsr_list);
jcr->needs_sd = true;
return jcr->ExpectedFiles;
bail_out:
free_ua_context(ua);
- free_bsr(rx.bsr);
+ free_bsr(rx.bsr_list);
return files;
}
+/*
+ * Given: a JobId in jcr->previous_jr.JobId,
+ * this subroutine writes a bsr file to restore that job.
+ * Returns: -1 on error
+ * number of files if OK
+ */
+int create_restore_bootstrap_file(JCR *jcr)
+{
+ return create_restore_bootstrap_file(jcr, jcr->previous_jr.JobId, 1, jcr->previous_jr.JobFiles);
+}
+
/* TODO: redirect command ouput to job log */
bool run_console_command(JCR *jcr, const char *cmd)
{
} else {
ok = do_a_command(ua);
}
+ close_db(ua);
free_ua_context(ua);
free_jcr(ljcr);
return ok;