diff --git a/Cargo.lock b/Cargo.lock index b999ae0e..7afff551 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,11 @@ [root] name = "watchexec" -version = "1.1.0" +version = "1.1.1" dependencies = [ "clap 2.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "notify 2.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index fab14f32..797375d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ lto = true [dependencies] glob = "0.2.11" +libc = "0.2.16" log = "0.3.6" notify = "2.6.3" diff --git a/src/main.rs b/src/main.rs index 124b875e..c9186499 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,9 @@ +#![feature(process_exec)] + #[macro_use] extern crate clap; extern crate env_logger; +extern crate libc; #[macro_use] extern crate log; extern crate notify; diff --git a/src/runner.rs b/src/runner.rs index 94033960..489c2f9f 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -1,3 +1,4 @@ +use libc; use std::process::{Child, Command}; pub struct Runner { @@ -11,7 +12,7 @@ impl Runner { Runner { process: None, restart: restart, - cls: clear, + cls: clear } } @@ -25,6 +26,22 @@ impl Runner { let _ = Command::new("clear").status(); } + #[cfg(target_family = "windows")] + fn kill(child: &mut Child) { + let _ = child.kill(); + } + + #[cfg(target_family = "unix")] + fn kill(child: &mut Child) { + extern { + fn killpg(pgrp: libc::pid_t, sig: libc::c_int) -> libc::c_int; + } + + unsafe { + killpg(child.id() as i32, libc::SIGTERM); + } + } + #[cfg(target_family = "windows")] fn invoke(&self, cmd: &str, updated_paths: Vec<&str>) -> Option { let mut command = Command::new("cmd.exe"); @@ -39,6 +56,8 @@ impl Runner { #[cfg(target_family = "unix")] fn invoke(&self, cmd: &str, updated_paths: Vec<&str>) -> Option { + use std::os::unix::process::CommandExt; + let mut command = Command::new("sh"); command.arg("-c").arg(cmd); @@ -46,18 +65,21 @@ impl Runner { command.env("WATCHEXEC_UPDATED_PATH", updated_paths[0]); } - command.spawn().ok() + command + .before_exec(|| unsafe { libc::setpgid(0, 0); Ok(()) }) + .spawn() + .ok() } pub fn run_command(&mut self, cmd: &str, updated_paths: Vec<&str>) { if let Some(ref mut child) = self.process { if self.restart { debug!("Killing child process (pid: {})", child.id()); - let _ = child.kill(); + Runner::kill(child); } debug!("Waiting for child process (pid: {})", child.id()); - let _ = child.wait(); + Runner::wait(child); } if self.cls { @@ -68,4 +90,19 @@ impl Runner { self.process = self.invoke(cmd, updated_paths); } + + #[cfg(target_family = "windows")] + fn wait(child: &mut Child) { + let _ = child.wait(); + } + + #[cfg(target_family = "unix")] + fn wait(child: &mut Child) { + unsafe { + let pid = child.id() as i32; + let status: Box = Box::new(0); + libc::waitpid(-pid, Box::into_raw(status), 0); + } + } + }