+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;
+ }
+ Dmsg0(100, "Connected to file daemon\n");
+ 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;
+ }
+ Dmsg0(200, "Connected to storage daemon\n");
+ 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.
+ */
+static int cancel_inactive_job(UAContext *ua, JCR *jcr)
+{
+ CLIENT_DBR cr;
+ JOB_DBR jr;
+ int i;
+ USTORE store;
+ CLIENT *client;
+
+ if (!jcr->client) {
+ memset(&cr, 0, sizeof(cr));
+
+ /* 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));
+
+ 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;
+ }
+ }
+
+ 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;
+ }
+ } else {
+ goto bail_out;
+ }
+ }
+
+ 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(ua->jcr, &store);
+
+ cancel_sd_job(ua, "cancel", jcr);
+
+bail_out:
+ return 1;
+}