+void sd_msg_thread_send_signal(JCR *jcr, int sig)
+{
+ jcr->lock();
+ if ( !jcr->sd_msg_thread_done
+ && jcr->SD_msg_chan_started
+ && !pthread_equal(jcr->SD_msg_chan, pthread_self()))
+ {
+ Dmsg1(800, "Send kill to SD msg chan jid=%d\n", jcr->JobId);
+ pthread_kill(jcr->SD_msg_chan, sig);
+ }
+ jcr->unlock();
+}
+
+static bool cancel_file_daemon_job(UAContext *ua, const char *cmd, JCR *jcr)
+{
+ CLIENT *old_client;
+
+ if (!jcr->client) {
+ Dmsg0(100, "No client to cancel\n");
+ return false;
+ }
+ old_client = ua->jcr->client;
+ ua->jcr->client = jcr->client;
+ if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
+ ua->error_msg(_("Failed to connect to File daemon.\n"));
+ ua->jcr->client = old_client;
+ return false;
+ }
+ Dmsg3(10, "Connected to file daemon %s for cancel ua.jcr=%p jcr=%p\n",
+ ua->jcr->client->name(), ua->jcr, jcr);
+ BSOCK *fd = ua->jcr->file_bsock;
+ fd->fsend("%s Job=%s\n", cmd, jcr->Job);
+ while (fd->recv() >= 0) {
+ ua->send_msg("%s", fd->msg);
+ }
+ fd->signal(BNET_TERMINATE);
+ free_bsock(ua->jcr->file_bsock);
+ ua->jcr->client = old_client;
+ return true;
+}
+
+static bool cancel_sd_job(UAContext *ua, const char *cmd, JCR *jcr)
+{
+ if (jcr->store_bsock) {
+ if (jcr->rstorage) {
+ copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource"));
+ } else {
+ copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource"));
+ }
+ } else {
+ USTORE store;
+ if (jcr->rstorage) {
+ store.store = jcr->rstore;
+ } else {
+ store.store = jcr->wstore;
+ }
+ set_wstorage(ua->jcr, &store);
+ }
+
+ if (!ua->jcr->wstore) {
+ ua->error_msg(_("Failed to select Storage daemon.\n"));
+ return false;
+ }
+
+ if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
+ ua->error_msg(_("Failed to connect to Storage daemon.\n"));
+ return false;
+ }
+
+ Dmsg3(10, "Connected to storage daemon %s for cancel ua.jcr=%p jcr=%p\n",
+ ua->jcr->wstore->name(), ua->jcr, jcr);
+
+ BSOCK *sd = ua->jcr->store_bsock;
+ sd->fsend("%s Job=%s\n", cmd, jcr->Job);
+ while (sd->recv() >= 0) {
+ ua->send_msg("%s", sd->msg);
+ }
+ sd->signal(BNET_TERMINATE);
+ free_bsock(ua->jcr->store_bsock);
+ return true;
+}
+
+/* The FD is not connected, so we try to complete JCR fields and send
+ * the cancel command.
+ */
+int cancel_inactive_job(UAContext *ua)
+{
+ CLIENT_DBR cr;
+ JOB_DBR jr;
+ int i;
+ USTORE store;
+ CLIENT *client;
+ JCR *jcr = new_jcr(sizeof(JCR), dird_free_jcr);
+
+ memset(&jr, 0, sizeof(jr));
+ memset(&cr, 0, sizeof(cr));
+
+ if ((i = find_arg_with_value(ua, "jobid")) > 0) {
+ jr.JobId = str_to_int64(ua->argv[i]);
+
+ } else if ((i = find_arg_with_value(ua, "ujobid")) > 0) {
+ bstrncpy(jr.Job, ua->argv[i], sizeof(jr.Job));
+
+ } else {
+ ua->error_msg(_("jobid/ujobid argument not found.\n"));
+ 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
+ * the job record
+ */
+ store.store = get_storage_resource(ua, false/*no default*/, true/*unique*/);
+ if (!store.store) {
+ goto bail_out;
+ }
+
+ set_wstorage(jcr, &store);
+ cancel_sd_job(ua, "cancel", jcr);
+
+bail_out:
+ jcr->JobId = 0;
+ free_jcr(jcr);
+ return 1;
+}