implementation based on and docs taken verbatim from `cargo_util::ProcessBuilder::exec_replace` Replaces the current process with the target process. On Unix, this executes the process using the Unix syscall `execvp`, which will block this process, and will only return if there is an error. On Windows this isn't technically possible. Instead we emulate it to the best of our ability. One aspect
(cmd: &mut Command)
| 90 | /// pretty quickly, and if the child handles the signal then we won't terminate |
| 91 | /// (and we shouldn't!) until the process itself later exits. |
| 92 | pub(crate) fn exec_replace(cmd: &mut Command) -> io::Result<ExitCode> { |
| 93 | #[cfg(unix)] |
| 94 | { |
| 95 | use std::os::unix::process::CommandExt; |
| 96 | // if exec() succeeds, it diverges, so the function just returns an io::Error |
| 97 | let err = cmd.exec(); |
| 98 | Err(err) |
| 99 | } |
| 100 | #[cfg(windows)] |
| 101 | { |
| 102 | use windows_sys::Win32::Foundation::{BOOL, FALSE, TRUE}; |
| 103 | use windows_sys::Win32::System::Console::SetConsoleCtrlHandler; |
| 104 | |
| 105 | unsafe extern "system" fn ctrlc_handler(_: u32) -> BOOL { |
| 106 | // Do nothing. Let the child process handle it. |
| 107 | TRUE |
| 108 | } |
| 109 | unsafe { |
| 110 | if SetConsoleCtrlHandler(Some(ctrlc_handler), TRUE) == FALSE { |
| 111 | return Err(io::Error::other("Unable to set console handler")); |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | cmd.status() |
| 116 | .map(|status| ExitCode::from(status.code().unwrap_or(1).try_into().unwrap_or(1))) |
| 117 | } |
| 118 | } |