From 7d562920c2fbf1341ed1ac0459ff69474c56d726 Mon Sep 17 00:00:00 2001
From: 4lDO2 <4lDO2@protonmail.com>
Date: Thu, 20 Jun 2024 14:21:11 +0200
Subject: [PATCH] Add sigaction boilerplate.

---
 redox-rt/src/signal.rs       | 84 ++++++++++++++++++++++++++++--------
 src/header/signal/redox.rs   | 16 +++----
 src/platform/redox/signal.rs | 58 +++++++++++++++++++++++--
 3 files changed, 128 insertions(+), 30 deletions(-)

diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 0d628506..676f839b 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -2,7 +2,7 @@ use core::cell::Cell;
 use core::ffi::c_int;
 use core::sync::atomic::{AtomicU64, Ordering};
 
-use syscall::{Result, Sigcontrol, SIGCHLD, SIGCONT, SIGURG, SIGWINCH};
+use syscall::{Error, Result, Sigcontrol, EINVAL, SIGCHLD, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGWINCH};
 
 use crate::arch::*;
 use crate::sync::Mutex;
@@ -101,6 +101,54 @@ fn modify_sigmask(old: Option<&mut u64>, op: Option<impl FnMut(u32, bool) -> u32
     Ok(())
 }
 
+#[derive(Clone, Copy)]
+pub enum Sigaction {
+    Default,
+    Ignore,
+    Handled {
+        handler: SignalHandler,
+        mask: u64,
+        flags: SigactionFlags,
+    },
+}
+pub fn sigaction(signal: u8, new: Option<&Sigaction>, old: Option<&mut Sigaction>) -> Result<()> {
+    if matches!(usize::from(signal), 0 | 32 | SIGKILL | SIGSTOP | 65..) {
+        return Err(Error::new(EINVAL));
+    }
+
+    let _sigguard = tmp_disable_signals();
+    let ctl = current_sigctl();
+    let guard = SIGACTIONS.lock();
+    let old_ignmask = IGNMASK.load(Ordering::Relaxed);
+
+    if let Some(old) = old {
+    }
+
+    let Some(new) = new else {
+        return Ok(());
+    };
+
+    match (usize::from(signal), new) {
+        (_, Sigaction::Ignore) | (SIGCHLD | SIGURG | SIGWINCH, Sigaction::Default) => {
+            IGNMASK.store(old_ignmask | sig_bit(signal.into()), Ordering::Relaxed);
+
+            // mark the signal as masked
+            ctl.word[usize::from(signal) / 32].fetch_or(1 << ((signal - 1) % 32), Ordering::Relaxed);
+
+            // POSIX specifies that pending signals shall be discarded if set to SIG_IGN by
+            // sigaction.
+            // TODO: handle tmp_disable_signals
+        }
+        (SIGTSTP, Sigaction::Default) => (), // stop
+        (SIGTTIN, Sigaction::Default) => (), // stop
+        (SIGTTOU, Sigaction::Default) => (), // stop
+        (_, Sigaction::Default) => (),
+        (_, Sigaction::Handled { .. }) => (),
+    }
+
+    todo!()
+}
+
 extern "C" {
     pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol;
 }
@@ -137,16 +185,18 @@ impl Drop for TmpDisableSignalsGuard {
     }
 }
 
-#[derive(Clone, Copy)]
-struct SignalAction {
-    handler: SignalHandler,
-    flags: SigactionFlags,
-    mask: u64,
-}
 bitflags::bitflags! {
+    // Some flags are ignored by the rt, but they match relibc's 1:1 to simplify conversion.
     #[derive(Clone, Copy)]
-    struct SigactionFlags: u32 {
-        const SA_RESETHAND = 1;
+    pub struct SigactionFlags: u32 {
+        const NOCLDSTOP = 1;
+        const NOCLDWAIT = 2;
+        const SIGINFO = 4;
+        const RESTORER = 0x0400_0000;
+        const ONSTACK = 0x0800_0000;
+        const RESTART = 0x1000_0000;
+        const NODEFER = 0x4000_0000;
+        const RESETHAND = 0x8000_0000;
     }
 }
 fn default_term_handler(sig: c_int) {
@@ -161,22 +211,18 @@ fn stop_handler_sentinel(_: c_int) {
 }
 
 #[derive(Clone, Copy)]
-union SignalHandler {
-    sa_handler: Option<extern "C" fn(c_int)>,
-    sa_sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>,
+pub union SignalHandler {
+    pub handler: Option<extern "C" fn(c_int)>,
+    pub sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>,
 }
 
 struct TheDefault {
-    actions: [SignalAction; 64],
+    actions: [Sigaction; 64],
     ignmask: u64,
 }
 
-static SIGACTIONS: Mutex<[SignalAction; 64]> = Mutex::new([SignalAction {
-    handler: SignalHandler { sa_handler: None },
-    flags: SigactionFlags::empty(),
-    mask: 0,
-}; 64]);
-static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH) | sig_bit(SIGCONT));
+static SIGACTIONS: Mutex<[Sigaction; 64]> = Mutex::new([Sigaction::Default; 64]);
+static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH));
 
 fn expand_mask(mask: u64) -> [u64; 2] {
     [mask & 0xffff_ffff, mask >> 32]
diff --git a/src/header/signal/redox.rs b/src/header/signal/redox.rs
index f146dcda..f21c168e 100644
--- a/src/header/signal/redox.rs
+++ b/src/header/signal/redox.rs
@@ -69,14 +69,14 @@ pub const NSIG: usize = 32;
 pub const SIGRTMIN: usize = 35;
 pub const SIGRTMAX: usize = 64;
 
-pub const SA_NOCLDSTOP: usize = 0x00000001;
-pub const SA_NOCLDWAIT: usize = 0x00000002;
-pub const SA_SIGINFO: usize = 0x00000004;
-pub const SA_RESTORER: usize = 0x04000000;
-pub const SA_ONSTACK: usize = 0x08000000;
-pub const SA_RESTART: usize = 0x10000000;
-pub const SA_NODEFER: usize = 0x40000000;
-pub const SA_RESETHAND: usize = 0x80000000;
+pub const SA_NOCLDSTOP: usize = 0x0000_0001;
+pub const SA_NOCLDWAIT: usize = 0x0000_0002;
+pub const SA_SIGINFO: usize = 0x0000_0004;
+pub const SA_RESTORER: usize = 0x0400_0000;
+pub const SA_ONSTACK: usize = 0x0800_0000;
+pub const SA_RESTART: usize = 0x1000_0000;
+pub const SA_NODEFER: usize = 0x4000_0000;
+pub const SA_RESETHAND: usize = 0x8000_0000;
 
 pub const SS_ONSTACK: usize = 0x00000001;
 pub const SS_DISABLE: usize = 0x00000002;
diff --git a/src/platform/redox/signal.rs b/src/platform/redox/signal.rs
index f8f82a8d..625ac730 100644
--- a/src/platform/redox/signal.rs
+++ b/src/platform/redox/signal.rs
@@ -1,4 +1,5 @@
 use core::mem;
+use redox_rt::signal::{Sigaction, SigactionFlags, SignalHandler};
 use syscall::{self, Result};
 
 use super::{
@@ -8,7 +9,7 @@ use super::{
 use crate::{
     header::{
         errno::{EINVAL, ENOSYS},
-        signal::{sigaction, siginfo_t, sigset_t, stack_t, SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK},
+        signal::{sigaction, siginfo_t, sigset_t, stack_t, SA_SIGINFO, SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK},
         sys_time::{itimerval, ITIMER_REAL},
         time::timespec,
     },
@@ -104,8 +105,59 @@ impl PalSignal for Sys {
         0
     }
 
-    fn sigaction(sig: c_int, act: Option<&sigaction>, oact: Option<&mut sigaction>) -> Result<(), Errno> {
-        todo!()
+    fn sigaction(sig: c_int, c_act: Option<&sigaction>, c_oact: Option<&mut sigaction>) -> Result<(), Errno> {
+        let sig = u8::try_from(sig).map_err(|_| syscall::Error::new(syscall::EINVAL))?;
+
+        let new_action = c_act.map(|c_act| {
+            let handler = c_act.sa_handler.map_or(0, |f| f as usize);
+
+            if handler == SIG_DFL {
+                Sigaction::Default
+            } else if handler == SIG_IGN {
+                Sigaction::Ignore
+            } else {
+                Sigaction::Handled {
+                    handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as u64 != 0 {
+                        SignalHandler { sigaction: unsafe { core::mem::transmute(c_act.sa_handler) } }
+                    } else {
+                        SignalHandler { handler: c_act.sa_handler }
+                    },
+                    mask: c_act.sa_mask,
+                    flags: SigactionFlags::from_bits_retain(c_act.sa_flags as u32),
+                }
+            }
+        });
+        let mut old_action = c_oact.as_ref().map(|_| Sigaction::Default);
+
+        redox_rt::signal::sigaction(sig, new_action.as_ref(), old_action.as_mut())?;
+
+        if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
+            *c_oact = match old_action {
+                Sigaction::Ignore => sigaction {
+                    sa_handler: unsafe { core::mem::transmute(SIG_IGN) },
+                    sa_flags: 0,
+                    sa_restorer: None,
+                    sa_mask: 0,
+                },
+                Sigaction::Default => sigaction {
+                    sa_handler: unsafe { core::mem::transmute(SIG_DFL) },
+                    sa_flags: 0,
+                    sa_restorer: None,
+                    sa_mask: 0,
+                },
+                Sigaction::Handled { handler, mask, flags } => sigaction {
+                    sa_handler: if flags.contains(SigactionFlags::SIGINFO) {
+                        unsafe { core::mem::transmute(handler.sigaction) }
+                    } else {
+                        unsafe { handler.handler }
+                    },
+                    sa_restorer: None,
+                    sa_flags: flags.bits().into(),
+                    sa_mask: mask,
+                },
+            };
+        }
+        Ok(())
     }
 
     unsafe fn sigaltstack(ss: *const stack_t, old_ss: *mut stack_t) -> c_int {
-- 
GitLab