Try to gracefully terminal child process before using SIGKILL (#4890)

This commit is contained in:
Michael Vines 2019-07-01 14:08:30 -07:00 committed by GitHub
parent 38b44f2496
commit 0999225794
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 2 deletions

1
Cargo.lock generated
View File

@ -2529,6 +2529,7 @@ dependencies = [
"indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"reqwest 0.9.18 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.94 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -24,6 +24,7 @@ dirs = "2.0.1"
indicatif = "0.11.0"
lazy_static = "1.3.0"
log = "0.4.2"
nix = "0.14.1"
reqwest = "0.9.18"
ring = "0.13.2"
serde = "1.0.94"

View File

@ -1,4 +1,5 @@
use crate::config::Config;
use crate::stop_process::stop_process;
use crate::update_manifest::{SignedUpdateManifest, UpdateManifest};
use chrono::{Local, TimeZone};
use console::{style, Emoji};
@ -793,8 +794,9 @@ pub fn run(
Ok(true) => {
// Update successful, kill current process so it will be restart
if let Some(ref mut child) = child_option {
let id = child.id();
println!("Killing pid {}: {:?}", id, child.kill());
stop_process(child).unwrap_or_else(|err| {
eprintln!("Failed to stop child: {:?}", err);
});
}
}
Ok(false) => {} // No update available

View File

@ -8,6 +8,7 @@ mod build_env;
mod command;
mod config;
mod defaults;
mod stop_process;
mod update_manifest;
// Return an error if a url cannot be parsed.

View File

@ -0,0 +1,67 @@
use std::io;
use std::process::Child;
fn kill_process(process: &mut Child) -> Result<(), io::Error> {
if let Ok(()) = process.kill() {
process.wait()?;
} else {
println!("Process {} has already exited", process.id());
}
Ok(())
}
#[cfg(windows)]
pub fn stop_process(process: &mut Child) -> Result<(), io::Error> {
kill_process(process)
}
#[cfg(not(windows))]
pub fn stop_process(process: &mut Child) -> Result<(), io::Error> {
use nix::errno::Errno::{EINVAL, EPERM, ESRCH};
use nix::sys::signal::{kill, Signal};
use nix::unistd::Pid;
use nix::Error::Sys;
use std::io::ErrorKind;
use std::thread;
use std::time::{Duration, Instant};
let nice_wait = Duration::from_secs(5);
let pid = Pid::from_raw(process.id() as i32);
match kill(pid, Signal::SIGINT) {
Ok(()) => {
let expire = Instant::now() + nice_wait;
while let Ok(None) = process.try_wait() {
if Instant::now() > expire {
break;
}
thread::sleep(nice_wait / 10);
}
if let Ok(None) = process.try_wait() {
kill_process(process)?;
}
}
Err(Sys(EINVAL)) => {
println!("Invalid signal. Killing process {}", pid);
kill_process(process)?;
}
Err(Sys(EPERM)) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Insufficient permissions to signal process {}", pid),
));
}
Err(Sys(ESRCH)) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Process {} does not exist", pid),
));
}
Err(e) => {
return Err(io::Error::new(
ErrorKind::InvalidInput,
format!("Unexpected error {}", e),
));
}
};
Ok(())
}