Skip to main content

ant_core/node/process/
detach.rs

1use std::process::Command;
2
3use crate::error::{Error, Result};
4
5/// Spawn a command detached from the current session.
6/// Returns the PID of the detached process.
7///
8/// On Unix: uses setsid to create a new session, redirects stdio to /dev/null.
9/// On Windows: uses CREATE_NO_WINDOW | DETACHED_PROCESS creation flags.
10pub fn spawn_detached(cmd: &str, args: &[&str]) -> Result<u32> {
11    spawn_detached_inner(cmd, args)
12}
13
14#[cfg(unix)]
15fn spawn_detached_inner(cmd: &str, args: &[&str]) -> Result<u32> {
16    use std::os::unix::process::CommandExt;
17    use std::process::Stdio;
18
19    // Safety: pre_exec runs between fork and exec in the child process.
20    // setsid() creates a new session, detaching from the controlling terminal.
21    let child = unsafe {
22        Command::new(cmd)
23            .args(args)
24            .stdin(Stdio::null())
25            .stdout(Stdio::null())
26            .stderr(Stdio::null())
27            .pre_exec(|| {
28                libc::setsid();
29                Ok(())
30            })
31            .spawn()
32    }
33    .map_err(|e| Error::ProcessSpawn(format!("Failed to spawn detached process: {e}")))?;
34
35    Ok(child.id())
36}
37
38#[cfg(windows)]
39fn spawn_detached_inner(cmd: &str, args: &[&str]) -> Result<u32> {
40    use std::os::windows::process::CommandExt;
41    use std::process::Stdio;
42
43    const CREATE_NO_WINDOW: u32 = 0x08000000;
44    const DETACHED_PROCESS: u32 = 0x00000008;
45
46    let child = Command::new(cmd)
47        .args(args)
48        .stdin(Stdio::null())
49        .stdout(Stdio::null())
50        .stderr(Stdio::null())
51        .creation_flags(CREATE_NO_WINDOW | DETACHED_PROCESS)
52        .spawn()
53        .map_err(|e| Error::ProcessSpawn(format!("Failed to spawn detached process: {e}")))?;
54
55    Ok(child.id())
56}