2024-07-26 10:56:19 -07:00
|
|
|
#[cfg(all(feature = "smol", not(feature = "tokio")))]
|
|
|
|
|
use smol::io::AsyncReadExt;
|
2024-07-24 18:06:11 -07:00
|
|
|
use std::fs::File;
|
|
|
|
|
use std::io;
|
2024-07-26 10:56:19 -07:00
|
|
|
use std::os::fd::OwnedFd;
|
2023-11-14 16:55:06 -05:00
|
|
|
use std::process::{exit, Command, Stdio};
|
2024-07-26 10:56:19 -07:00
|
|
|
#[cfg(feature = "tokio")]
|
2024-07-25 09:26:54 -07:00
|
|
|
use tokio::io::AsyncReadExt;
|
2023-11-14 16:55:06 -05:00
|
|
|
|
2024-07-26 10:56:19 -07:00
|
|
|
#[cfg(feature = "tokio")]
|
|
|
|
|
async fn read_from_pipe(read: OwnedFd) -> Option<u32> {
|
|
|
|
|
let mut read = tokio::net::unix::pipe::Receiver::from_owned_fd(read).unwrap();
|
|
|
|
|
read.read_u32().await.ok()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(all(feature = "smol", not(feature = "tokio")))]
|
|
|
|
|
async fn read_from_pipe(read: OwnedFd) -> Option<u32> {
|
|
|
|
|
let mut read = smol::Async::new(std::fs::File::from(read)).unwrap();
|
|
|
|
|
let mut bytes = [0; 4];
|
|
|
|
|
read.read_exact(&mut bytes).await.ok()?;
|
|
|
|
|
Some(u32::from_be_bytes(bytes))
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-14 16:55:06 -05:00
|
|
|
/// Performs a double fork with setsid to spawn and detach a command.
|
2024-07-25 09:26:54 -07:00
|
|
|
pub async fn spawn(mut command: Command) -> Option<u32> {
|
2025-03-08 00:43:13 +02:00
|
|
|
// NOTE: Windows platform is not supported
|
2023-11-14 16:55:06 -05:00
|
|
|
command
|
|
|
|
|
.stdin(Stdio::null())
|
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
|
.stderr(Stdio::null());
|
|
|
|
|
|
2025-03-08 00:43:13 +02:00
|
|
|
// Handle Linux
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2024-07-24 18:06:11 -07:00
|
|
|
let Ok((read, write)) = rustix::pipe::pipe_with(rustix::pipe::PipeFlags::CLOEXEC) else {
|
|
|
|
|
return None;
|
|
|
|
|
};
|
2023-11-14 16:55:06 -05:00
|
|
|
|
2025-03-08 00:43:13 +02:00
|
|
|
// Handle macOS
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
let Ok((read, write)) = rustix::pipe::pipe() else {
|
|
|
|
|
return None;
|
|
|
|
|
};
|
|
|
|
|
|
2024-07-24 18:06:11 -07:00
|
|
|
match unsafe { libc::fork() } {
|
|
|
|
|
// Parent process
|
2024-07-25 09:26:54 -07:00
|
|
|
1.. => {
|
2024-07-26 10:56:19 -07:00
|
|
|
// Drop copy of write end, then read PID from pipe
|
2024-07-25 09:26:54 -07:00
|
|
|
drop(write);
|
2024-08-22 10:32:07 -04:00
|
|
|
let pid = read_from_pipe(read).await;
|
|
|
|
|
// wait to prevent zombie
|
|
|
|
|
_ = rustix::process::wait(rustix::process::WaitOptions::empty());
|
|
|
|
|
pid
|
2024-07-24 18:06:11 -07:00
|
|
|
}
|
2023-11-14 16:55:06 -05:00
|
|
|
|
2024-07-24 18:06:11 -07:00
|
|
|
// Child process
|
|
|
|
|
0 => {
|
|
|
|
|
let _res = rustix::process::setsid();
|
|
|
|
|
if let Ok(child) = command.spawn() {
|
|
|
|
|
// Write PID to pipe
|
2024-07-25 09:26:54 -07:00
|
|
|
let _ = rustix::io::write(write, &child.id().to_be_bytes());
|
2023-11-14 16:55:06 -05:00
|
|
|
}
|
2024-07-24 18:06:11 -07:00
|
|
|
|
|
|
|
|
exit(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
..=-1 => {
|
|
|
|
|
println!(
|
|
|
|
|
"failed to fork and spawn command: {}",
|
|
|
|
|
io::Error::last_os_error()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
None
|
2023-11-14 16:55:06 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|