xcelerate_core/stealth/
process.rs1use std::process::Command;
2use std::sync::Mutex;
3use once_cell::sync::Lazy;
4use crate::error::{XcelerateResult, XcelerateError};
5
6#[cfg(windows)]
7use std::os::windows::process::CommandExt;
8
9#[cfg(unix)]
10use std::os::unix::process::CommandExt;
11
12pub static REGISTERED_PIDS: Lazy<Mutex<Vec<u32>>> = Lazy::new(|| Mutex::new(Vec::new()));
14
15pub fn spawn_detached(mut cmd: Command) -> XcelerateResult<u32> {
19 #[cfg(windows)]
20 {
21 cmd.creation_flags(0x00000200 | 0x00000008);
24 }
25
26 #[cfg(unix)]
27 {
28 unsafe {
29 cmd.pre_exec(|| {
30 if libc::setsid() == -1 {
32 return Err(std::io::Error::last_os_error());
33 }
34 Ok(())
35 });
36 }
37 }
38
39 let child = cmd.spawn().map_err(|e| XcelerateError::NotFound(format!("Failed to spawn detached process: {}", e)))?;
40 let pid = child.id();
41
42 ProcessRegistry::register(pid);
44
45 Ok(pid)
46}
47
48pub struct ProcessGuard {
51 pub pid: u32,
52 pub auto_kill: bool,
53}
54
55impl Drop for ProcessGuard {
56 fn drop(&mut self) {
57 if self.auto_kill {
58 kill_pid(self.pid);
59 }
60
61 ProcessRegistry::unregister(self.pid);
63 }
64}
65
66pub fn kill_pid(pid: u32) {
68 #[cfg(windows)]
69 {
70 let _ = Command::new("taskkill")
71 .args(["/F", "/PID", &pid.to_string()])
72 .stdout(std::process::Stdio::null())
73 .stderr(std::process::Stdio::null())
74 .status();
75 }
76
77 #[cfg(unix)]
78 {
79 unsafe {
80 libc::kill(pid as i32, libc::SIGTERM);
81 }
82 }
83}
84
85pub fn cleanup_all() {
87 if let Ok(mut pids) = REGISTERED_PIDS.lock() {
88 for &pid in pids.iter() {
89 kill_pid(pid);
90 }
91 pids.clear();
92 }
93}
94
95pub struct ProcessRegistry;
96
97impl ProcessRegistry {
98 pub fn register(pid: u32) {
99 if let Ok(mut pids) = REGISTERED_PIDS.lock() {
100 pids.push(pid);
101 }
102 }
103
104 pub fn unregister(pid: u32) {
105 if let Ok(mut pids) = REGISTERED_PIDS.lock() {
106 pids.retain(|&p| p != pid);
107 }
108 }
109
110 pub fn cleanup() {
111 cleanup_all();
112 }
113}