4

I have a function which creates a process on Windows.

pub fn create_process(url: String) {
    thread::spawn(move || {
        let _child = process::Command::new("cmd.exe")
            .arg("/C")
            .arg("ping")
            .arg(&url)
            .arg("-t")
            .spawn()
            .expect("Couldn't run 'ping'");
    });
}

I have a function which I want to terminate (kill) the process created by 'create_process()':

pub fn stop() {
    // ?????
}

How can I access the _child created in create_process function to terminate its process? Are there any other ways to kill that process?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Andrew
  • 107
  • 2
  • 12

1 Answers1

12

TL;DR: Use the kill method. For example:

use std::{process, thread, time::Duration};

fn main() {
    let mut child = process::Command::new("ping")
        .arg("8.8.8.8")
        .arg("-t")
        .spawn()
        .expect("Couldn't run 'ping'");

    thread::sleep(Duration::from_secs(5));
    child.kill().expect("!kill");
}

Notice how you don't need a separate thread, since the spawned process is already parallel to the parent process.

In your question, there is a code example which uses "cmd /C" to run the "ping". This spawns not one but two processes: the "cmd" process and the "ping" process. Killing the child will kill the "cmd" process but might leave the "ping" process running.

Using "cmd /C" is also dangerous, allowing for command injection.

How can I access the _child created in the create_process function to terminate its process?

The _child is Send, which means that you can send it from thread to thread. The particulars of sending data across threads is likely to have been covered already in a number of corresponding Stack Overflow questions.

Are there any other ways to kill that process?

You can use the native platform APIs. For example:

[dependencies]
gstuff = "0.5.2"
winapi = {version = "0.3.6", features = ["psapi", "shellapi"]}
#[macro_use]
extern crate gstuff;

use std::process;
use std::ptr::null_mut;
use std::thread;
use std::time::Duration;
use winapi::shared::minwindef::DWORD;
use winapi::shared::ntdef::HANDLE;
use winapi::um::processthreadsapi::{OpenProcess, TerminateProcess};
use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_TERMINATE};

struct Process(HANDLE);
impl Process {
    fn open(pid: DWORD) -> Result<Process, String> {
        // https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx
        let pc = unsafe { OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, 0, pid) };
        if pc == null_mut() {
            return ERR!("!OpenProcess");
        }
        Ok(Process(pc))
    }

    fn kill(self) -> Result<(), String> {
        unsafe { TerminateProcess(self.0, 1) };
        Ok(())
    }
}
impl Drop for Process {
    fn drop(&mut self) {
        unsafe { winapi::um::handleapi::CloseHandle(self.0) };
    }
}

fn main() {
    let child = process::Command::new("ping")
        .arg("8.8.8.8")
        .arg("-t")
        .spawn()
        .expect("Couldn't run 'ping'");

    let pid = child.id();
    let pc = Process::open(pid as DWORD).expect("!open");
    println!("Process {} opened.", pid);
    thread::sleep(Duration::from_secs(5));
    pc.kill().expect("!kill");
    println!("Process {} killed.", pid);
}
Eliaz Bobadilla
  • 479
  • 4
  • 16
ArtemGr
  • 11,684
  • 3
  • 52
  • 85