ferrijs_std/utils/
signals.rs1use rquickjs::{prelude::Opt, Ctx, Exception, Result, Value};
4
5use crate::utils::result::ResultExt;
6use std::io;
7
8#[cfg(unix)]
9macro_rules! generate_signal_from_str_fn {
10 ($($signal:path),*) => {
11 pub fn signal_from_str(signal: &str) -> Option<i32> {
12 let signal = ["libc::", signal].concat();
13 match signal.as_str() {
14 $(stringify!($signal) => Some($signal),)*
15 _ => None,
16 }
17 }
18
19 pub fn signal_str_from_i32(signal: i32) -> Option<&'static str> {
20 $(if signal == $signal {
21 return Some(&stringify!($signal)[6..]);
22 })*
23 None
24 }
25 };
26}
27
28#[cfg(unix)]
29generate_signal_from_str_fn!(
30 libc::SIGHUP,
31 libc::SIGINT,
32 libc::SIGQUIT,
33 libc::SIGILL,
34 libc::SIGABRT,
35 libc::SIGFPE,
36 libc::SIGKILL,
37 libc::SIGSEGV,
38 libc::SIGPIPE,
39 libc::SIGALRM,
40 libc::SIGTERM
41);
42
43#[cfg(not(unix))]
44static WINDOWS_SIGTERM: i32 = -1;
45
46pub fn parse_signal(signal: Option<Value<'_>>) -> Result<i32> {
47 let Some(val) = signal else {
48 #[cfg(unix)]
49 return Ok(libc::SIGTERM);
50 #[cfg(not(unix))]
51 return Ok(WINDOWS_SIGTERM);
52 };
53
54 if let Some(num) = val.as_number() {
55 let sig = num as i32;
56 #[cfg(unix)]
57 return Ok(sig);
58 #[cfg(not(unix))]
60 return Ok(if sig == 0 { 0 } else { WINDOWS_SIGTERM });
61 }
62
63 if let Some(str_val) = val.as_string() {
64 let s = str_val.to_string()?;
65
66 #[cfg(unix)]
67 let mapped_sig = signal_from_str(&s);
68
69 #[cfg(not(unix))]
70 let mapped_sig = match s.as_str() {
71 "SIGINT" | "SIGTERM" | "SIGKILL" | "SIGQUIT" | "SIGHUP" | "SIGUSR1" => {
72 Some(WINDOWS_SIGTERM)
73 },
74 _ => None,
75 };
76
77 return match mapped_sig {
78 Some(sig) => Ok(sig),
79 None => Err(Exception::throw_type(
80 val.ctx(),
81 &format!("Unknown signal: {}", s),
82 )),
83 };
84 }
85
86 Err(Exception::throw_type(val.ctx(), "Invalid signal type"))
87}
88
89#[cfg(unix)]
90pub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> {
91 if unsafe { libc::kill(pid as i32, signal) } == 0 {
94 Ok(())
95 } else {
96 Err(io::Error::last_os_error())
97 }
98}
99
100#[cfg(windows)]
101pub fn kill_process_raw(pid: u32, signal: i32) -> io::Result<()> {
102 use windows_sys::Win32::Foundation::CloseHandle;
103 use windows_sys::Win32::System::Threading::{OpenProcess, TerminateProcess, PROCESS_TERMINATE};
104
105 let handle = unsafe { OpenProcess(PROCESS_TERMINATE, 0, pid) };
107 if handle == std::ptr::null_mut() {
108 return Err(io::Error::last_os_error());
109 }
110
111 let result = if signal == 0 {
112 Ok(())
113 } else {
114 if unsafe { TerminateProcess(handle, 1) } != 0 {
116 Ok(())
117 } else {
118 Err(io::Error::last_os_error())
119 }
120 };
121
122 unsafe { CloseHandle(handle) };
124 result
125}
126
127pub fn kill(ctx: &Ctx<'_>, pid: u32, signal: Opt<Value<'_>>) -> Result<bool> {
128 let signal = parse_signal(signal.0)?;
129
130 kill_process_raw(pid, signal)
131 .map(|_| true)
132 .or_else(|e| {
133 #[cfg(unix)]
137 let is_not_found = e.raw_os_error() == Some(libc::ESRCH); #[cfg(windows)]
140 let is_not_found = true; if signal == 0 && is_not_found {
143 Ok(false)
144 } else {
145 Err(e)
146 }
147 })
148 .or_throw(ctx)
149}