From 0ddb10cbd65727d014c342819e35737696e2c438 Mon Sep 17 00:00:00 2001 From: Chris Pick Date: Mon, 13 Nov 2023 19:47:08 -0500 Subject: [PATCH] Add `signal::sigaction_current()` Provide a way to query the currently installed sigaction. The decision to add `sigaction_current()` instead of just exposing the `sigaction_inner()` function was to avoid any confusion over the semantics of passing in a `None` `sigaction` argument (eg: someone thinking that it meant remove or reset the action). This builds towards #2172. --- src/sys/signal.rs | 32 +++++++++++++++++++++++++------ test/sys/test_signal.rs | 42 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/sys/signal.rs b/src/sys/signal.rs index e3274f27e9..d019766d00 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -849,6 +849,16 @@ impl SigAction { } } +unsafe fn sigaction_inner(signal: Signal, sigaction: Option<&SigAction>) -> Result { + let mut oldact = mem::MaybeUninit::::uninit(); + + let res = libc::sigaction(signal as libc::c_int, + sigaction.map_or(ptr::null(), |sigaction| &sigaction.sigaction as *const libc::sigaction), + oldact.as_mut_ptr()); + + Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) +} + /// Changes the action taken by a process on receipt of a specific signal. /// /// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the previous @@ -867,13 +877,23 @@ impl SigAction { /// pointer is valid. In that case, this function effectively dereferences a /// raw pointer of unknown provenance. pub unsafe fn sigaction(signal: Signal, sigaction: &SigAction) -> Result { - let mut oldact = mem::MaybeUninit::::uninit(); - - let res = libc::sigaction(signal as libc::c_int, - &sigaction.sigaction as *const libc::sigaction, - oldact.as_mut_ptr()); + sigaction_inner(signal, Some(sigaction)) +} - Errno::result(res).map(|_| SigAction { sigaction: oldact.assume_init() }) +/// Gets the current action a process will take on receipt of a specific signal. +/// +/// `signal` can be any signal except `SIGKILL` or `SIGSTOP`. On success, it returns the current +/// action for the given signal. The current action will always remain in place, unchanged. +/// +/// # Safety +/// +/// There is no guarantee that the old signal handler was installed +/// correctly. If it was installed by this crate, it will be. But if it was +/// installed by, for example, C code, then there is no guarantee its function +/// pointer is valid. In that case, this function effectively dereferences a +/// raw pointer of unknown provenance. +pub unsafe fn sigaction_current(signal: Signal) -> Result { + sigaction_inner(signal, None) } /// Signal management (see [signal(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/signal.html)) diff --git a/test/sys/test_signal.rs b/test/sys/test_signal.rs index bb8d5ea5cd..2d72ab6da3 100644 --- a/test/sys/test_signal.rs +++ b/test/sys/test_signal.rs @@ -35,6 +35,48 @@ fn test_old_sigaction_flags() { unsafe { sigaction(SIGINT, &oact) }.unwrap(); } +#[test] +fn test_current_sigaction() { + let _m = crate::SIGNAL_MTX.lock(); + + let oact = unsafe { + sigaction( + SIGINT, + &SigAction::new( + SigHandler::SigDfl, + SaFlags::empty(), + SigSet::empty(), + ), + ) + } + .unwrap(); + + assert_eq!( + unsafe { sigaction_current(SIGINT) }.unwrap().handler(), + SigHandler::SigDfl + ); + + unsafe { + sigaction( + SIGINT, + &SigAction::new( + SigHandler::SigIgn, + SaFlags::empty(), + SigSet::empty(), + ), + ) + } + .unwrap(); + + assert_eq!( + unsafe { sigaction_current(SIGINT) }.unwrap().handler(), + SigHandler::SigIgn + ); + + // restore original + unsafe { sigaction(SIGINT, &oact) }.unwrap(); +} + #[test] fn test_sigprocmask_noop() { sigprocmask(SigmaskHow::SIG_BLOCK, None, None)