use std::io;
use super::kernel_abi::KernelSigAction;
use super::syscall::rt_sigaction_raw;
use super::SA_RESTART;
#[cfg(target_arch = "x86_64")]
use super::{trampoline::varta_signal_restorer, SA_RESTORER};
pub(super) unsafe fn install(handler: extern "C" fn(i32)) -> io::Result<()> {
const SIGINT: i32 = 2;
const SIGTERM: i32 = 15;
let mut act = std::mem::MaybeUninit::<KernelSigAction>::zeroed();
unsafe {
(*act.as_mut_ptr()).sa_handler = handler as *const ();
#[cfg(target_arch = "x86_64")]
{
(*act.as_mut_ptr()).sa_flags = SA_RESTART | SA_RESTORER;
(*act.as_mut_ptr()).sa_restorer = varta_signal_restorer as *const ();
}
#[cfg(not(target_arch = "x86_64"))]
{
(*act.as_mut_ptr()).sa_flags = SA_RESTART;
}
}
let act = unsafe { act.assume_init() };
let install_one = |sig: i32| -> io::Result<()> {
let rc = unsafe { rt_sigaction_raw(sig, &act, std::ptr::null_mut()) };
if rc < 0 {
return Err(io::Error::from_raw_os_error(-rc as i32));
}
let mut old = std::mem::MaybeUninit::<KernelSigAction>::zeroed();
let rc2 = unsafe { rt_sigaction_raw(sig, std::ptr::null(), old.as_mut_ptr()) };
if rc2 < 0 {
return Err(io::Error::from_raw_os_error(-rc2 as i32));
}
let old = unsafe { old.assume_init() };
if old.sa_handler != handler as *const () {
return Err(io::Error::new(
io::ErrorKind::Other,
"rt_sigaction readback: kernel reports a different sa_handler than we installed",
));
}
if old.sa_flags & SA_RESTART == 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
"rt_sigaction readback: kernel did not preserve SA_RESTART",
));
}
#[cfg(target_arch = "x86_64")]
{
if old.sa_flags & SA_RESTORER == 0 {
return Err(io::Error::new(
io::ErrorKind::Other,
"rt_sigaction readback: SA_RESTORER not set in installed action \
(libc wrapper hijacked the syscall?)",
));
}
if old.sa_restorer != varta_signal_restorer as *const () {
return Err(io::Error::new(
io::ErrorKind::Other,
"rt_sigaction readback: kernel did not install our trampoline \
(libc override, or kernel rt_sigreturn ABI changed?)",
));
}
}
Ok(())
};
install_one(SIGINT)?;
install_one(SIGTERM)?;
Ok(())
}
pub(super) unsafe fn install_one_direct(
sig: i32,
handler: extern "C" fn(i32),
old_out: *mut KernelSigAction,
) -> io::Result<()> {
let mut act = std::mem::MaybeUninit::<KernelSigAction>::zeroed();
unsafe {
(*act.as_mut_ptr()).sa_handler = handler as *const ();
#[cfg(target_arch = "x86_64")]
{
(*act.as_mut_ptr()).sa_flags = SA_RESTART | SA_RESTORER;
(*act.as_mut_ptr()).sa_restorer = varta_signal_restorer as *const ();
}
#[cfg(not(target_arch = "x86_64"))]
{
(*act.as_mut_ptr()).sa_flags = SA_RESTART;
}
}
let act = unsafe { act.assume_init() };
let rc = unsafe { rt_sigaction_raw(sig, &act, old_out) };
if rc < 0 {
return Err(io::Error::from_raw_os_error(-rc as i32));
}
Ok(())
}