diff --git a/brush-core/src/traps.rs b/brush-core/src/traps.rs index bab309b73..1e63c6d6c 100644 --- a/brush-core/src/traps.rs +++ b/brush-core/src/traps.rs @@ -231,12 +231,19 @@ impl TrapHandlerConfig { /// * `signal_type` - The type of signal to register a handler for. /// * `command` - The command to execute when the signal is trapped. /// * `source_info` - The source info for where the trap handler was defined. + /// + /// Signals recorded as ignored at shell entry remain ignored, so registration attempts for + /// them are silently declined. pub fn register_handler( &mut self, signal_type: TrapSignal, command: String, source_info: crate::SourceInfo, ) { + if self.ignored_signal_name_at_entry(signal_type).is_some() { + return; + } + let _ = self.handlers.insert( signal_type, TrapHandler { @@ -284,4 +291,44 @@ mod tests { assert_eq!(ignored, vec![(10, "SIGUSR1")]); } + + #[test] + fn ignored_signal_at_entry_cannot_be_trapped_or_reset() { + let Some(signal) = crate::sys::signal::Signal::iterator().next() else { + return; + }; + let trap_signal = TrapSignal::Signal(signal); + let mut traps = TrapHandlerConfig::default(); + traps.record_ignored_signal_at_entry(signal as i32, signal.as_str().to_owned()); + + traps.register_handler( + trap_signal, + "echo caught".to_owned(), + crate::SourceInfo::default(), + ); + traps.remove_handlers(trap_signal); + + assert!(!traps.handles(trap_signal)); + assert_eq!( + traps.ignored_signal_name_at_entry(trap_signal), + Some(signal.as_str()) + ); + } + + #[test] + fn signal_not_ignored_at_entry_can_be_trapped() { + let Some(signal) = crate::sys::signal::Signal::iterator().next() else { + return; + }; + let trap_signal = TrapSignal::Signal(signal); + let mut traps = TrapHandlerConfig::default(); + + traps.register_handler( + trap_signal, + "echo caught".to_owned(), + crate::SourceInfo::default(), + ); + + assert!(traps.handles(trap_signal)); + } } diff --git a/brush-shell/tests/cases/compat/builtins/trap.yaml b/brush-shell/tests/cases/compat/builtins/trap.yaml index 4e0b11e0f..1b07f1c7b 100644 --- a/brush-shell/tests/cases/compat/builtins/trap.yaml +++ b/brush-shell/tests/cases/compat/builtins/trap.yaml @@ -562,6 +562,20 @@ cases: stdin: | bash -c 'trap "" USR1; exec "$1" --norc --noprofile -c "trap -p USR1; (trap -p USR1)"' _ "$0" + - name: "signals ignored at shell entry cannot be trapped or reset" + stdin: | + bash -c 'trap "" USR1; signal=$(kill -l USR1); exec "$1" --norc --noprofile -c "$2" _ "$signal"' _ "$0" ' + trap "echo named" USR1 + trap -p USR1 + trap - USR1 + trap -p USR1 + trap "echo numeric" "$1" + trap -p "$1" + trap - "$1" + trap -p "$1" + (trap "echo subshell" USR1; trap -p USR1) + ' + - name: "trap -p - with specific signal" stdin: | trap 'echo "[int]"' INT