Try to gracefully terminal child process before using SIGKILL (#4890)
This commit is contained in:
@ -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
|
||||
|
@ -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.
|
||||
|
67
install/src/stop_process.rs
Normal file
67
install/src/stop_process.rs
Normal 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(())
|
||||
}
|
Reference in New Issue
Block a user