vv-agent 0.6.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use std::process::{Child, Command};

#[cfg(unix)]
pub(super) fn configure_process_group(command: &mut Command) {
    use std::os::unix::process::CommandExt;

    unsafe {
        command.pre_exec(|| {
            if libc::setsid() == -1 {
                return Err(std::io::Error::last_os_error());
            }
            Ok(())
        });
    }
}

#[cfg(windows)]
pub(super) fn configure_process_group(command: &mut Command) {
    use std::os::windows::process::CommandExt;

    command.creation_flags(windows_hidden_process_creation_flags());
}

#[cfg(all(not(unix), not(windows)))]
pub(super) fn configure_process_group(_command: &mut Command) {}

#[cfg(unix)]
pub(super) fn kill_process_group_or_child(child: &mut Child, force: bool) {
    let signal = if force { libc::SIGKILL } else { libc::SIGTERM };
    let pid = child.id() as libc::pid_t;
    unsafe {
        if libc::kill(-pid, signal) == -1 {
            let _ = child.kill();
        }
    }
}

#[cfg(windows)]
pub(super) fn kill_process_group_or_child(child: &mut Child, _force: bool) {
    use std::process::Stdio;

    let taskkill = Command::new("taskkill")
        .args(windows_taskkill_args(child.id()))
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status();
    if !taskkill.map(|status| status.success()).unwrap_or(false) {
        let _ = child.kill();
    }
}

#[cfg(all(not(unix), not(windows)))]
pub(super) fn kill_process_group_or_child(child: &mut Child, _force: bool) {
    let _ = child.kill();
}

#[cfg(any(windows, test))]
fn windows_hidden_process_creation_flags() -> u32 {
    const CREATE_NEW_PROCESS_GROUP: u32 = 0x0000_0200;
    const CREATE_NO_WINDOW: u32 = 0x0800_0000;
    CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW
}

#[cfg(any(windows, test))]
fn windows_taskkill_args(pid: u32) -> Vec<String> {
    vec![
        "/PID".to_string(),
        pid.to_string(),
        "/T".to_string(),
        "/F".to_string(),
    ]
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn windows_hidden_process_creation_flags_match_agent_subprocess_defaults() {
        assert_eq!(
            windows_hidden_process_creation_flags(),
            0x0000_0200 | 0x0800_0000
        );
    }

    #[test]
    fn windows_taskkill_args_match_agent_process_tree_termination() {
        assert_eq!(
            windows_taskkill_args(1234),
            vec!["/PID", "1234", "/T", "/F"]
        );
    }
}