1mod cond;
37mod state;
38
39pub use self::cond::Condition;
40pub use self::state::{Action, Origin, SetActionError, TrapState};
41use self::state::{EnterSubshellOption, GrandState};
42use crate::Env;
43use crate::signal;
44use crate::source::Location;
45#[cfg(doc)]
46use crate::system::Concurrent;
47use crate::system::{Disposition, Errno, Signals};
48use std::collections::BTreeMap;
49use std::collections::btree_map::Entry;
50use std::pin::Pin;
51use std::rc::Rc;
52
53pub trait SignalSystem: Signals {
55 fn get_disposition(&self, signal: signal::Number) -> Result<Disposition, Errno>;
61
62 fn set_disposition(
72 &self,
73 signal: signal::Number,
74 disposition: Disposition,
75 ) -> impl Future<Output = Result<Disposition, Errno>> + use<Self>;
76}
77
78impl<S: SignalSystem> SignalSystem for Rc<S> {
80 #[inline]
81 fn get_disposition(&self, signal: signal::Number) -> Result<Disposition, Errno> {
82 (self as &S).get_disposition(signal)
83 }
84 #[inline]
85 fn set_disposition(
86 &self,
87 signal: signal::Number,
88 disposition: Disposition,
89 ) -> impl Future<Output = Result<Disposition, Errno>> + use<S> {
90 (self as &S).set_disposition(signal, disposition)
91 }
92}
93
94#[must_use]
98pub struct Iter<'a> {
99 inner: std::collections::btree_map::Iter<'a, Condition, GrandState>,
100}
101
102impl<'a> Iterator for Iter<'a> {
103 type Item = (&'a Condition, &'a TrapState, Option<&'a TrapState>);
108
109 fn next(&mut self) -> Option<(&'a Condition, &'a TrapState, Option<&'a TrapState>)> {
110 self.inner
111 .next()
112 .map(|(cond, state)| (cond, state.current_state(), state.parent_state()))
113 }
114}
115
116#[derive(Clone, Debug, Default)]
120pub struct TrapSet {
121 traps: BTreeMap<Condition, GrandState>,
122}
123
124impl TrapSet {
125 pub fn get_state<C: Into<Condition>>(
141 &self,
142 cond: C,
143 ) -> (Option<&TrapState>, Option<&TrapState>) {
144 self.get_state_impl(cond.into())
145 }
146
147 fn get_state_impl(&self, cond: Condition) -> (Option<&TrapState>, Option<&TrapState>) {
148 match self.traps.get(&cond) {
149 None => (None, None),
150 Some(state) => (Some(state.current_state()), state.parent_state()),
151 }
152 }
153
154 pub fn peek_state<S: SignalSystem, C: Into<Condition>>(
172 &mut self,
173 system: &S,
174 cond: C,
175 ) -> Result<&TrapState, Errno> {
176 self.peek_state_impl(system, cond.into())
177 }
178
179 fn peek_state_impl<S: SignalSystem>(
180 &mut self,
181 system: &S,
182 cond: Condition,
183 ) -> Result<&TrapState, Errno> {
184 let entry = self.traps.entry(cond);
185 let state = GrandState::insert_from_system_if_vacant(system, entry)?;
186 Ok(state.parent_state().unwrap_or(state.current_state()))
187 }
188
189 pub async fn set_action<S: SignalSystem, C: Into<Condition>>(
208 &mut self,
209 system: &S,
210 cond: C,
211 action: Action,
212 origin: Location,
213 override_ignore: bool,
214 ) -> Result<(), SetActionError> {
215 self.set_action_impl(system, cond.into(), action, origin, override_ignore)
216 .await
217 }
218
219 async fn set_action_impl<S: SignalSystem>(
220 &mut self,
221 system: &S,
222 cond: Condition,
223 action: Action,
224 origin: Location,
225 override_ignore: bool,
226 ) -> Result<(), SetActionError> {
227 if let Condition::Signal(signal) = cond {
228 if signal == S::SIGKILL {
229 return Err(SetActionError::SIGKILL);
230 }
231 if signal == S::SIGSTOP {
232 return Err(SetActionError::SIGSTOP);
233 }
234 }
235
236 self.clear_parent_states();
237
238 let entry = self.traps.entry(cond);
239 GrandState::set_action(system, entry, action, origin, override_ignore).await
240 }
241
242 fn clear_parent_states(&mut self) {
243 for state in self.traps.values_mut() {
244 state.clear_parent_state();
245 }
246 }
247
248 #[inline]
260 pub fn iter(&self) -> Iter<'_> {
261 let inner = self.traps.iter();
262 Iter { inner }
263 }
264
265 pub async fn enter_subshell<S: SignalSystem>(
301 &mut self,
302 system: &S,
303 ignore_sigint_sigquit: bool,
304 keep_internal_dispositions_for_stoppers: bool,
305 ) {
306 self.clear_parent_states();
307
308 for (&cond, state) in &mut self.traps {
309 let option = match cond {
310 Condition::Exit => EnterSubshellOption::ClearInternalDisposition,
311 Condition::Signal(signal) =>
312 {
313 #[allow(clippy::if_same_then_else)]
314 if signal == S::SIGCHLD {
315 EnterSubshellOption::KeepInternalDisposition
316 } else if ignore_sigint_sigquit && (signal == S::SIGINT || signal == S::SIGQUIT)
317 {
318 EnterSubshellOption::Ignore
319 } else if keep_internal_dispositions_for_stoppers
320 && (signal == S::SIGTSTP || signal == S::SIGTTIN || signal == S::SIGTTOU)
321 && state.internal_disposition() != Disposition::Default
322 {
323 EnterSubshellOption::Ignore
324 } else {
325 EnterSubshellOption::ClearInternalDisposition
326 }
327 }
328 };
329 state.enter_subshell(system, cond, option).await.ok();
330 }
331
332 if ignore_sigint_sigquit {
333 for signal in [S::SIGINT, S::SIGQUIT] {
334 match self.traps.entry(Condition::Signal(signal)) {
335 Entry::Vacant(vacant) => {
336 GrandState::ignore(system, vacant).await.unwrap_or_default()
337 }
338 Entry::Occupied(_) => {}
340 }
341 }
342 }
343 }
344
345 pub fn catch_signal(&mut self, signal: signal::Number) {
350 if let Some(state) = self.traps.get_mut(&Condition::Signal(signal)) {
351 state.mark_as_caught();
352 }
353 }
354
355 pub fn take_signal_if_caught(&mut self, signal: signal::Number) -> Option<&TrapState> {
359 self.traps
360 .get_mut(&Condition::Signal(signal))
361 .and_then(|state| state.handle_if_caught())
362 }
363
364 pub fn take_caught_signal(&mut self) -> Option<(signal::Number, &TrapState)> {
372 self.traps.iter_mut().find_map(|(&cond, state)| match cond {
373 Condition::Signal(signal) => state.handle_if_caught().map(|trap| (signal, trap)),
374 _ => None,
375 })
376 }
377
378 async fn set_internal_disposition<S: SignalSystem>(
379 &mut self,
380 signal: signal::Number,
381 disposition: Disposition,
382 system: &S,
383 ) -> Result<(), Errno> {
384 let entry = self.traps.entry(Condition::Signal(signal));
385 GrandState::set_internal_disposition(system, entry, disposition).await
386 }
387
388 pub async fn enable_internal_disposition_for_sigchld<S: SignalSystem>(
398 &mut self,
399 system: &S,
400 ) -> Result<(), Errno> {
401 self.set_internal_disposition(S::SIGCHLD, Disposition::Catch, system)
402 .await
403 }
404
405 pub async fn enable_internal_dispositions_for_terminators<S: SignalSystem>(
414 &mut self,
415 system: &S,
416 ) -> Result<(), Errno> {
417 self.set_internal_disposition(S::SIGINT, Disposition::Catch, system)
418 .await?;
419 self.set_internal_disposition(S::SIGTERM, Disposition::Ignore, system)
420 .await?;
421 self.set_internal_disposition(S::SIGQUIT, Disposition::Ignore, system)
422 .await
423 }
424
425 pub async fn enable_internal_dispositions_for_stoppers<S: SignalSystem>(
434 &mut self,
435 system: &S,
436 ) -> Result<(), Errno> {
437 self.set_internal_disposition(S::SIGTSTP, Disposition::Ignore, system)
438 .await?;
439 self.set_internal_disposition(S::SIGTTIN, Disposition::Ignore, system)
440 .await?;
441 self.set_internal_disposition(S::SIGTTOU, Disposition::Ignore, system)
442 .await
443 }
444
445 pub async fn disable_internal_dispositions_for_terminators<S: SignalSystem>(
447 &mut self,
448 system: &S,
449 ) -> Result<(), Errno> {
450 self.set_internal_disposition(S::SIGINT, Disposition::Default, system)
451 .await?;
452 self.set_internal_disposition(S::SIGTERM, Disposition::Default, system)
453 .await?;
454 self.set_internal_disposition(S::SIGQUIT, Disposition::Default, system)
455 .await
456 }
457
458 pub async fn disable_internal_dispositions_for_stoppers<S: SignalSystem>(
460 &mut self,
461 system: &S,
462 ) -> Result<(), Errno> {
463 self.set_internal_disposition(S::SIGTSTP, Disposition::Default, system)
464 .await?;
465 self.set_internal_disposition(S::SIGTTIN, Disposition::Default, system)
466 .await?;
467 self.set_internal_disposition(S::SIGTTOU, Disposition::Default, system)
468 .await
469 }
470
471 pub async fn disable_internal_dispositions<S: SignalSystem>(
477 &mut self,
478 system: &S,
479 ) -> Result<(), Errno> {
480 self.set_internal_disposition(S::SIGCHLD, Disposition::Default, system)
481 .await?;
482 self.disable_internal_dispositions_for_terminators(system)
483 .await?;
484 self.disable_internal_dispositions_for_stoppers(system)
485 .await
486 }
487}
488
489impl<'a> IntoIterator for &'a TrapSet {
490 type Item = (&'a Condition, &'a TrapState, Option<&'a TrapState>);
495 type IntoIter = Iter<'a>;
496
497 #[inline(always)]
498 fn into_iter(self) -> Iter<'a> {
499 self.iter()
500 }
501}
502
503type PinFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
504
505pub struct RunSignalTrapIfCaught<S>(
532 pub for<'a> fn(
533 env: &'a mut Env<S>,
534 signal: signal::Number,
535 ) -> PinFuture<'a, Option<crate::semantics::Result>>,
536);
537
538impl<S> Clone for RunSignalTrapIfCaught<S> {
540 fn clone(&self) -> Self {
541 *self
542 }
543}
544
545impl<S> Copy for RunSignalTrapIfCaught<S> {}
546
547impl<S> std::fmt::Debug for RunSignalTrapIfCaught<S> {
548 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
549 f.debug_tuple("RunSignalTrapIfCaught")
550 .field(&self.0)
551 .finish()
552 }
553}
554
555#[cfg(test)]
556mod tests {
557 use super::*;
558 use crate::job::ProcessState;
559 use crate::system::SendSignal as _;
560 use crate::system::r#virtual::{
561 SIGABRT, SIGALRM, SIGBUS, SIGCHLD, SIGCONT, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGIOT,
562 SIGKILL, SIGPIPE, SIGPROF, SIGQUIT, SIGSEGV, SIGSTOP, SIGSYS, SIGTERM, SIGTRAP, SIGTSTP,
563 SIGTTIN, SIGTTOU, SIGURG, SIGUSR1, SIGUSR2, SIGVTALRM, SIGWINCH, SIGXCPU, SIGXFSZ,
564 };
565 use crate::test_helper::in_virtual_system;
566 use futures_util::FutureExt as _;
567 use std::cell::RefCell;
568 use std::collections::HashMap;
569 use std::future::ready;
570 use std::ops::RangeInclusive;
571
572 #[derive(Default)]
573 pub struct DummySystem(pub RefCell<HashMap<signal::Number, Disposition>>);
574
575 impl Signals for DummySystem {
576 const SIGABRT: signal::Number = SIGABRT;
577 const SIGALRM: signal::Number = SIGALRM;
578 const SIGBUS: signal::Number = SIGBUS;
579 const SIGCHLD: signal::Number = SIGCHLD;
580 const SIGCLD: Option<signal::Number> = None;
581 const SIGCONT: signal::Number = SIGCONT;
582 const SIGEMT: Option<signal::Number> = None;
583 const SIGFPE: signal::Number = SIGFPE;
584 const SIGHUP: signal::Number = SIGHUP;
585 const SIGILL: signal::Number = SIGILL;
586 const SIGINFO: Option<signal::Number> = None;
587 const SIGINT: signal::Number = SIGINT;
588 const SIGIO: Option<signal::Number> = None;
589 const SIGIOT: signal::Number = SIGIOT;
590 const SIGKILL: signal::Number = SIGKILL;
591 const SIGLOST: Option<signal::Number> = None;
592 const SIGPIPE: signal::Number = SIGPIPE;
593 const SIGPOLL: Option<signal::Number> = None;
594 const SIGPROF: signal::Number = SIGPROF;
595 const SIGPWR: Option<signal::Number> = None;
596 const SIGQUIT: signal::Number = SIGQUIT;
597 const SIGSEGV: signal::Number = SIGSEGV;
598 const SIGSTKFLT: Option<signal::Number> = None;
599 const SIGSTOP: signal::Number = SIGSTOP;
600 const SIGSYS: signal::Number = SIGSYS;
601 const SIGTERM: signal::Number = SIGTERM;
602 const SIGTHR: Option<signal::Number> = None;
603 const SIGTRAP: signal::Number = SIGTRAP;
604 const SIGTSTP: signal::Number = SIGTSTP;
605 const SIGTTIN: signal::Number = SIGTTIN;
606 const SIGTTOU: signal::Number = SIGTTOU;
607 const SIGURG: signal::Number = SIGURG;
608 const SIGUSR1: signal::Number = SIGUSR1;
609 const SIGUSR2: signal::Number = SIGUSR2;
610 const SIGVTALRM: signal::Number = SIGVTALRM;
611 const SIGWINCH: signal::Number = SIGWINCH;
612 const SIGXCPU: signal::Number = SIGXCPU;
613 const SIGXFSZ: signal::Number = SIGXFSZ;
614
615 fn sigrt_range(&self) -> Option<RangeInclusive<signal::Number>> {
616 None
617 }
618 }
619
620 impl SignalSystem for DummySystem {
621 fn get_disposition(&self, signal: signal::Number) -> Result<Disposition, Errno> {
622 Ok(self.0.borrow().get(&signal).copied().unwrap_or_default())
623 }
624
625 fn set_disposition(
626 &self,
627 signal: signal::Number,
628 disposition: Disposition,
629 ) -> impl Future<Output = Result<Disposition, Errno>> + use<> {
630 ready(Ok(self
631 .0
632 .borrow_mut()
633 .insert(signal, disposition)
634 .unwrap_or_default()))
635 }
636 }
637
638 #[test]
639 fn default_trap() {
640 let trap_set = TrapSet::default();
641 assert_eq!(trap_set.get_state(SIGCHLD), (None, None));
642 }
643
644 #[test]
645 fn setting_trap_for_two_signals() {
646 let system = DummySystem::default();
647 let mut trap_set = TrapSet::default();
648 let origin_1 = Location::dummy("foo");
649 let result = trap_set
650 .set_action(&system, SIGUSR1, Action::Ignore, origin_1.clone(), false)
651 .now_or_never()
652 .unwrap();
653 assert_eq!(result, Ok(()));
654
655 let command = Action::Command("echo".into());
656 let origin_2 = Location::dummy("bar");
657 let result = trap_set
658 .set_action(&system, SIGUSR2, command.clone(), origin_2.clone(), false)
659 .now_or_never()
660 .unwrap();
661 assert_eq!(result, Ok(()));
662
663 assert_eq!(
664 trap_set.get_state(SIGUSR1),
665 (
666 Some(&TrapState {
667 action: Action::Ignore,
668 origin: Origin::User(origin_1),
669 pending: false
670 }),
671 None
672 )
673 );
674 assert_eq!(
675 trap_set.get_state(SIGUSR2),
676 (
677 Some(&TrapState {
678 action: command,
679 origin: Origin::User(origin_2),
680 pending: false
681 }),
682 None
683 )
684 );
685 assert_eq!(system.0.borrow()[&SIGUSR1], Disposition::Ignore);
686 assert_eq!(system.0.borrow()[&SIGUSR2], Disposition::Catch);
687 }
688
689 #[test]
690 fn setting_trap_for_sigkill() {
691 let system = DummySystem::default();
692 let mut trap_set = TrapSet::default();
693 let origin = Location::dummy("origin");
694 let result = trap_set
695 .set_action(&system, SIGKILL, Action::Ignore, origin, false)
696 .now_or_never()
697 .unwrap();
698 assert_eq!(result, Err(SetActionError::SIGKILL));
699 assert_eq!(trap_set.get_state(SIGKILL), (None, None));
700 assert_eq!(system.0.borrow().get(&SIGKILL), None);
701 }
702
703 #[test]
704 fn setting_trap_for_sigstop() {
705 let system = DummySystem::default();
706 let mut trap_set = TrapSet::default();
707 let origin = Location::dummy("origin");
708 let result = trap_set
709 .set_action(&system, SIGSTOP, Action::Ignore, origin, false)
710 .now_or_never()
711 .unwrap();
712 assert_eq!(result, Err(SetActionError::SIGSTOP));
713 assert_eq!(trap_set.get_state(SIGSTOP), (None, None));
714 assert_eq!(system.0.borrow().get(&SIGSTOP), None);
715 }
716
717 #[test]
718 fn peeking_state_with_default_inherited_disposition() {
719 let system = DummySystem::default();
720 let mut trap_set = TrapSet::default();
721 let result = trap_set.peek_state(&system, SIGCHLD);
722 assert_eq!(
723 result,
724 Ok(&TrapState {
725 action: Action::Default,
726 origin: Origin::Inherited,
727 pending: false
728 })
729 );
730 }
731
732 #[test]
733 fn peeking_state_with_inherited_disposition_of_ignore() {
734 let system = DummySystem::default();
735 system.0.borrow_mut().insert(SIGCHLD, Disposition::Ignore);
736 let mut trap_set = TrapSet::default();
737 let result = trap_set.peek_state(&system, SIGCHLD);
738 assert_eq!(
739 result,
740 Ok(&TrapState {
741 action: Action::Ignore,
742 origin: Origin::Inherited,
743 pending: false
744 })
745 );
746 }
747
748 #[test]
749 fn peeking_state_with_parent_state() {
750 let system = DummySystem::default();
751 let mut trap_set = TrapSet::default();
752 let origin = Location::dummy("foo");
753 let command = Action::Command("echo".into());
754 trap_set
755 .set_action(&system, SIGUSR1, command.clone(), origin.clone(), false)
756 .now_or_never()
757 .unwrap()
758 .unwrap();
759 trap_set
760 .enter_subshell(&system, false, false)
761 .now_or_never()
762 .unwrap();
763
764 let result = trap_set.peek_state(&system, SIGUSR1);
765 assert_eq!(
766 result,
767 Ok(&TrapState {
768 action: command,
769 origin: Origin::User(origin),
770 pending: false
771 })
772 );
773 }
774
775 #[test]
776 fn basic_iteration() {
777 let system = DummySystem::default();
778 let mut trap_set = TrapSet::default();
779 let origin_1 = Location::dummy("foo");
780 trap_set
781 .set_action(&system, SIGUSR1, Action::Ignore, origin_1.clone(), false)
782 .now_or_never()
783 .unwrap()
784 .unwrap();
785 let command = Action::Command("echo".into());
786 let origin_2 = Location::dummy("bar");
787 trap_set
788 .set_action(&system, SIGUSR2, command.clone(), origin_2.clone(), false)
789 .now_or_never()
790 .unwrap()
791 .unwrap();
792
793 let mut i = trap_set.iter();
794 let first = i.next().unwrap();
795 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
796 assert_eq!(first.1.action, Action::Ignore);
797 assert_eq!(first.1.origin, Origin::User(origin_1));
798 assert_eq!(first.2, None);
799 let second = i.next().unwrap();
800 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
801 assert_eq!(second.1.action, command);
802 assert_eq!(second.1.origin, Origin::User(origin_2));
803 assert_eq!(first.2, None);
804 assert_eq!(i.next(), None);
805 }
806
807 #[test]
808 fn iteration_after_entering_subshell() {
809 let system = DummySystem::default();
810 let mut trap_set = TrapSet::default();
811 let origin_1 = Location::dummy("foo");
812 trap_set
813 .set_action(&system, SIGUSR1, Action::Ignore, origin_1.clone(), false)
814 .now_or_never()
815 .unwrap()
816 .unwrap();
817 let command = Action::Command("echo".into());
818 let origin_2 = Location::dummy("bar");
819 trap_set
820 .set_action(&system, SIGUSR2, command.clone(), origin_2.clone(), false)
821 .now_or_never()
822 .unwrap()
823 .unwrap();
824 trap_set
825 .enter_subshell(&system, false, false)
826 .now_or_never()
827 .unwrap();
828
829 let mut i = trap_set.iter();
830 let first = i.next().unwrap();
831 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
832 assert_eq!(first.1.action, Action::Ignore);
833 assert_eq!(first.1.origin, Origin::User(origin_1));
834 assert_eq!(first.2, None);
835 let second = i.next().unwrap();
836 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
837 assert_eq!(second.1.action, Action::Default);
838 assert_eq!(second.1.origin, Origin::Subshell);
839 assert_eq!(second.2.unwrap().action, command);
840 assert_eq!(second.2.unwrap().origin, Origin::User(origin_2));
841 assert_eq!(i.next(), None);
842 }
843
844 #[test]
845 fn iteration_after_setting_trap_in_subshell() {
846 let system = DummySystem::default();
847 let mut trap_set = TrapSet::default();
848 let origin_1 = Location::dummy("foo");
849 let command = Action::Command("echo".into());
850 trap_set
851 .set_action(&system, SIGUSR1, command, origin_1, false)
852 .now_or_never()
853 .unwrap()
854 .unwrap();
855 trap_set
856 .enter_subshell(&system, false, false)
857 .now_or_never()
858 .unwrap();
859 let origin_2 = Location::dummy("bar");
860 let command = Action::Command("ls".into());
861 trap_set
862 .set_action(&system, SIGUSR2, command.clone(), origin_2.clone(), false)
863 .now_or_never()
864 .unwrap()
865 .unwrap();
866
867 let mut i = trap_set.iter();
868 let first = i.next().unwrap();
869 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
870 assert_eq!(first.1.action, Action::Default);
871 assert_eq!(first.1.origin, Origin::Subshell);
872 assert_eq!(first.2, None);
873 let second = i.next().unwrap();
874 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
875 assert_eq!(second.1.action, command);
876 assert_eq!(second.1.origin, Origin::User(origin_2));
877 assert_eq!(second.2, None);
878 assert_eq!(i.next(), None);
879 }
880
881 #[test]
882 fn entering_subshell_resets_command_traps() {
883 let system = DummySystem::default();
884 let mut trap_set = TrapSet::default();
885 let action = Action::Command("".into());
886 let origin = Location::dummy("origin");
887 trap_set
888 .set_action(&system, SIGCHLD, action.clone(), origin.clone(), false)
889 .now_or_never()
890 .unwrap()
891 .unwrap();
892
893 trap_set
894 .enter_subshell(&system, false, false)
895 .now_or_never()
896 .unwrap();
897 assert_eq!(
898 trap_set.get_state(SIGCHLD),
899 (
900 Some(&TrapState {
901 action: Action::Default,
902 origin: Origin::Subshell,
903 pending: false
904 }),
905 Some(&TrapState {
906 action,
907 origin: Origin::User(origin),
908 pending: false
909 })
910 )
911 );
912 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Default);
913 }
914
915 #[test]
916 fn entering_subshell_keeps_ignore_traps() {
917 let system = DummySystem::default();
918 let mut trap_set = TrapSet::default();
919 let origin = Location::dummy("origin");
920 trap_set
921 .set_action(&system, SIGCHLD, Action::Ignore, origin.clone(), false)
922 .now_or_never()
923 .unwrap()
924 .unwrap();
925
926 trap_set
927 .enter_subshell(&system, false, false)
928 .now_or_never()
929 .unwrap();
930 assert_eq!(
931 trap_set.get_state(SIGCHLD),
932 (
933 Some(&TrapState {
934 action: Action::Ignore,
935 origin: Origin::User(origin),
936 pending: false
937 }),
938 None
939 )
940 );
941 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Ignore);
942 }
943
944 #[test]
945 fn entering_subshell_with_internal_disposition_for_sigchld() {
946 let system = DummySystem::default();
947 let mut trap_set = TrapSet::default();
948 let action = Action::Command("".into());
949 let origin = Location::dummy("origin");
950 trap_set
951 .set_action(&system, SIGCHLD, action.clone(), origin.clone(), false)
952 .now_or_never()
953 .unwrap()
954 .unwrap();
955 trap_set
956 .enable_internal_disposition_for_sigchld(&system)
957 .now_or_never()
958 .unwrap()
959 .unwrap();
960
961 trap_set
962 .enter_subshell(&system, false, false)
963 .now_or_never()
964 .unwrap();
965 assert_eq!(
966 trap_set.get_state(SIGCHLD),
967 (
968 Some(&TrapState {
969 action: Action::Default,
970 origin: Origin::Subshell,
971 pending: false
972 }),
973 Some(&TrapState {
974 action,
975 origin: Origin::User(origin),
976 pending: false
977 })
978 )
979 );
980 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Catch);
981 }
982
983 #[test]
984 fn entering_subshell_with_internal_disposition_for_sigint() {
985 let system = DummySystem::default();
986 let mut trap_set = TrapSet::default();
987 let action = Action::Command("".into());
988 let origin = Location::dummy("origin");
989 trap_set
990 .set_action(&system, SIGINT, action.clone(), origin.clone(), false)
991 .now_or_never()
992 .unwrap()
993 .unwrap();
994 trap_set
995 .enable_internal_dispositions_for_terminators(&system)
996 .now_or_never()
997 .unwrap()
998 .unwrap();
999
1000 trap_set
1001 .enter_subshell(&system, false, false)
1002 .now_or_never()
1003 .unwrap();
1004 assert_eq!(
1005 trap_set.get_state(SIGINT),
1006 (
1007 Some(&TrapState {
1008 action: Action::Default,
1009 origin: Origin::Subshell,
1010 pending: false
1011 }),
1012 Some(&TrapState {
1013 action,
1014 origin: Origin::User(origin),
1015 pending: false
1016 })
1017 )
1018 );
1019 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Default);
1020 }
1021
1022 #[test]
1023 fn entering_subshell_with_internal_disposition_for_sigterm() {
1024 let system = DummySystem::default();
1025 let mut trap_set = TrapSet::default();
1026 let action = Action::Command("".into());
1027 let origin = Location::dummy("origin");
1028 trap_set
1029 .set_action(&system, SIGTERM, action.clone(), origin.clone(), false)
1030 .now_or_never()
1031 .unwrap()
1032 .unwrap();
1033 trap_set
1034 .enable_internal_dispositions_for_terminators(&system)
1035 .now_or_never()
1036 .unwrap()
1037 .unwrap();
1038
1039 trap_set
1040 .enter_subshell(&system, false, false)
1041 .now_or_never()
1042 .unwrap();
1043 assert_eq!(
1044 trap_set.get_state(SIGTERM),
1045 (
1046 Some(&TrapState {
1047 action: Action::Default,
1048 origin: Origin::Subshell,
1049 pending: false
1050 }),
1051 Some(&TrapState {
1052 action,
1053 origin: Origin::User(origin),
1054 pending: false
1055 })
1056 )
1057 );
1058 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Default);
1059 }
1060
1061 #[test]
1062 fn entering_subshell_with_internal_disposition_for_sigquit() {
1063 let system = DummySystem::default();
1064 let mut trap_set = TrapSet::default();
1065 let action = Action::Command("".into());
1066 let origin = Location::dummy("origin");
1067 trap_set
1068 .set_action(&system, SIGQUIT, action.clone(), origin.clone(), false)
1069 .now_or_never()
1070 .unwrap()
1071 .unwrap();
1072 trap_set
1073 .enable_internal_dispositions_for_terminators(&system)
1074 .now_or_never()
1075 .unwrap()
1076 .unwrap();
1077
1078 trap_set
1079 .enter_subshell(&system, false, false)
1080 .now_or_never()
1081 .unwrap();
1082 assert_eq!(
1083 trap_set.get_state(SIGQUIT),
1084 (
1085 Some(&TrapState {
1086 action: Action::Default,
1087 origin: Origin::Subshell,
1088 pending: false
1089 }),
1090 Some(&TrapState {
1091 action,
1092 origin: Origin::User(origin),
1093 pending: false
1094 })
1095 )
1096 );
1097 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Default);
1098 }
1099
1100 #[test]
1101 fn entering_subshell_with_internal_disposition_for_sigtstp() {
1102 let system = DummySystem::default();
1103 let mut trap_set = TrapSet::default();
1104 let action = Action::Command("".into());
1105 let origin = Location::dummy("origin");
1106 trap_set
1107 .set_action(&system, SIGTSTP, action.clone(), origin.clone(), false)
1108 .now_or_never()
1109 .unwrap()
1110 .unwrap();
1111 trap_set
1112 .enable_internal_dispositions_for_stoppers(&system)
1113 .now_or_never()
1114 .unwrap()
1115 .unwrap();
1116
1117 trap_set
1118 .enter_subshell(&system, false, false)
1119 .now_or_never()
1120 .unwrap();
1121 assert_eq!(
1122 trap_set.get_state(SIGTSTP),
1123 (
1124 Some(&TrapState {
1125 action: Action::Default,
1126 origin: Origin::Subshell,
1127 pending: false
1128 }),
1129 Some(&TrapState {
1130 action,
1131 origin: Origin::User(origin),
1132 pending: false
1133 })
1134 )
1135 );
1136 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Default);
1137 }
1138
1139 #[test]
1140 fn entering_subshell_with_internal_disposition_for_sigttin() {
1141 let system = DummySystem::default();
1142 let mut trap_set = TrapSet::default();
1143 let action = Action::Command("".into());
1144 let origin = Location::dummy("origin");
1145 trap_set
1146 .set_action(&system, SIGTTIN, action.clone(), origin.clone(), false)
1147 .now_or_never()
1148 .unwrap()
1149 .unwrap();
1150 trap_set
1151 .enable_internal_dispositions_for_stoppers(&system)
1152 .now_or_never()
1153 .unwrap()
1154 .unwrap();
1155
1156 trap_set
1157 .enter_subshell(&system, false, false)
1158 .now_or_never()
1159 .unwrap();
1160 assert_eq!(
1161 trap_set.get_state(SIGTTIN),
1162 (
1163 Some(&TrapState {
1164 action: Action::Default,
1165 origin: Origin::Subshell,
1166 pending: false
1167 }),
1168 Some(&TrapState {
1169 action,
1170 origin: Origin::User(origin),
1171 pending: false
1172 })
1173 )
1174 );
1175 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Default);
1176 }
1177
1178 #[test]
1179 fn entering_subshell_with_internal_disposition_for_sigttou() {
1180 let system = DummySystem::default();
1181 let mut trap_set = TrapSet::default();
1182 let action = Action::Command("".into());
1183 let origin = Location::dummy("origin");
1184 trap_set
1185 .set_action(&system, SIGTTOU, action.clone(), origin.clone(), false)
1186 .now_or_never()
1187 .unwrap()
1188 .unwrap();
1189 trap_set
1190 .enable_internal_dispositions_for_stoppers(&system)
1191 .now_or_never()
1192 .unwrap()
1193 .unwrap();
1194
1195 trap_set
1196 .enter_subshell(&system, false, false)
1197 .now_or_never()
1198 .unwrap();
1199 assert_eq!(
1200 trap_set.get_state(SIGTTOU),
1201 (
1202 Some(&TrapState {
1203 action: Action::Default,
1204 origin: Origin::Subshell,
1205 pending: false
1206 }),
1207 Some(&TrapState {
1208 action,
1209 origin: Origin::User(origin),
1210 pending: false
1211 })
1212 )
1213 );
1214 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Default);
1215 }
1216
1217 #[test]
1218 fn setting_trap_after_entering_subshell_clears_parent_states() {
1219 let system = DummySystem::default();
1220 let mut trap_set = TrapSet::default();
1221 let origin_1 = Location::dummy("foo");
1222 let command = Action::Command("echo 1".into());
1223 trap_set
1224 .set_action(&system, SIGUSR1, command, origin_1, false)
1225 .now_or_never()
1226 .unwrap()
1227 .unwrap();
1228 let origin_2 = Location::dummy("bar");
1229 let command = Action::Command("echo 2".into());
1230 trap_set
1231 .set_action(&system, SIGUSR2, command, origin_2, false)
1232 .now_or_never()
1233 .unwrap()
1234 .unwrap();
1235 trap_set
1236 .enter_subshell(&system, false, false)
1237 .now_or_never()
1238 .unwrap();
1239
1240 let command = Action::Command("echo 9".into());
1241 let origin_3 = Location::dummy("qux");
1242 trap_set
1243 .set_action(&system, SIGUSR1, command.clone(), origin_3.clone(), false)
1244 .now_or_never()
1245 .unwrap()
1246 .unwrap();
1247
1248 assert_eq!(
1249 trap_set.get_state(SIGUSR1),
1250 (
1251 Some(&TrapState {
1252 action: command,
1253 origin: Origin::User(origin_3),
1254 pending: false
1255 }),
1256 None
1257 )
1258 );
1259 assert_eq!(
1260 trap_set.get_state(SIGUSR2),
1261 (
1262 Some(&TrapState {
1263 action: Action::Default,
1264 origin: Origin::Subshell,
1265 pending: false
1266 }),
1267 None
1268 )
1269 );
1270 assert_eq!(system.0.borrow()[&SIGUSR1], Disposition::Catch);
1271 assert_eq!(system.0.borrow()[&SIGUSR2], Disposition::Default);
1272 }
1273
1274 #[test]
1275 fn entering_nested_subshell_clears_parent_states() {
1276 let system = DummySystem::default();
1277 let mut trap_set = TrapSet::default();
1278 let origin_1 = Location::dummy("foo");
1279 let command = Action::Command("echo 1".into());
1280 trap_set
1281 .set_action(&system, SIGUSR1, command, origin_1, false)
1282 .now_or_never()
1283 .unwrap()
1284 .unwrap();
1285 let origin_2 = Location::dummy("bar");
1286 let command = Action::Command("echo 2".into());
1287 trap_set
1288 .set_action(&system, SIGUSR2, command, origin_2, false)
1289 .now_or_never()
1290 .unwrap()
1291 .unwrap();
1292 trap_set
1293 .enter_subshell(&system, false, false)
1294 .now_or_never()
1295 .unwrap();
1296 trap_set
1297 .enter_subshell(&system, false, false)
1298 .now_or_never()
1299 .unwrap();
1300
1301 assert_eq!(
1302 trap_set.get_state(SIGUSR1),
1303 (
1304 Some(&TrapState {
1305 action: Action::Default,
1306 origin: Origin::Subshell,
1307 pending: false
1308 }),
1309 None
1310 )
1311 );
1312 assert_eq!(
1313 trap_set.get_state(SIGUSR2),
1314 (
1315 Some(&TrapState {
1316 action: Action::Default,
1317 origin: Origin::Subshell,
1318 pending: false
1319 }),
1320 None
1321 )
1322 );
1323 assert_eq!(system.0.borrow()[&SIGUSR1], Disposition::Default);
1324 assert_eq!(system.0.borrow()[&SIGUSR2], Disposition::Default);
1325 }
1326
1327 #[test]
1328 fn ignoring_sigint_on_entering_subshell_with_action_set() {
1329 in_virtual_system(|mut env, state| async move {
1330 env.traps
1331 .set_action(
1332 &env.system,
1333 SIGINT,
1334 Action::Command("".into()),
1335 Location::dummy(""),
1336 false,
1337 )
1338 .await
1339 .unwrap();
1340 env.system.kill(env.main_pid, Some(SIGINT)).await.unwrap();
1341 env.traps.enter_subshell(&env.system, true, false).await;
1342
1343 let state = state.borrow();
1344 let process = &state.processes[&env.main_pid];
1345 assert_eq!(process.disposition(SIGINT), Disposition::Ignore);
1346 assert_eq!(process.state(), ProcessState::Running);
1347 })
1348 }
1349
1350 #[test]
1351 fn ignoring_sigquit_on_entering_subshell_with_action_set() {
1352 in_virtual_system(|mut env, state| async move {
1353 env.traps
1354 .set_action(
1355 &env.system,
1356 SIGQUIT,
1357 Action::Command("".into()),
1358 Location::dummy(""),
1359 false,
1360 )
1361 .await
1362 .unwrap();
1363 env.system.kill(env.main_pid, Some(SIGQUIT)).await.unwrap();
1364 env.traps.enter_subshell(&env.system, true, false).await;
1365
1366 let state = state.borrow();
1367 let process = &state.processes[&env.main_pid];
1368 assert_eq!(process.disposition(SIGQUIT), Disposition::Ignore);
1369 assert_eq!(process.state(), ProcessState::Running);
1370 })
1371 }
1372
1373 #[test]
1374 fn ignoring_sigint_and_sigquit_on_entering_subshell_without_action_set() {
1375 let system = DummySystem::default();
1376 let mut trap_set = TrapSet::default();
1377 trap_set
1378 .enter_subshell(&system, true, false)
1379 .now_or_never()
1380 .unwrap();
1381 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Ignore);
1382 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1383 }
1384
1385 #[test]
1386 fn keeping_stopper_internal_dispositions_ignored() {
1387 in_virtual_system(|mut env, state| async move {
1388 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1389 env.traps
1390 .set_action(
1391 &env.system,
1392 signal,
1393 Action::Command("".into()),
1394 Location::dummy(""),
1395 false,
1396 )
1397 .await
1398 .unwrap();
1399 }
1400 env.traps
1401 .enable_internal_dispositions_for_stoppers(&env.system)
1402 .await
1403 .unwrap();
1404 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1405 env.system.kill(env.main_pid, Some(signal)).await.unwrap();
1406 }
1407 env.traps.enter_subshell(&env.system, false, true).await;
1408
1409 let state = state.borrow();
1410 let process = &state.processes[&env.main_pid];
1411 assert_eq!(process.disposition(SIGTSTP), Disposition::Ignore);
1412 assert_eq!(process.disposition(SIGTTIN), Disposition::Ignore);
1413 assert_eq!(process.disposition(SIGTTOU), Disposition::Ignore);
1414 assert_eq!(process.state(), ProcessState::Running);
1415 })
1416 }
1417
1418 #[test]
1419 fn no_stopper_internal_dispositions_enabled_to_be_kept_ignored() {
1420 in_virtual_system(|mut env, state| async move {
1421 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1422 env.traps
1423 .set_action(
1424 &env.system,
1425 signal,
1426 Action::Command("".into()),
1427 Location::dummy(""),
1428 false,
1429 )
1430 .await
1431 .unwrap();
1432 }
1433 env.traps.enter_subshell(&env.system, false, true).await;
1434
1435 let state = state.borrow();
1436 let process = &state.processes[&env.main_pid];
1437 assert_eq!(process.disposition(SIGTSTP), Disposition::Default);
1438 assert_eq!(process.disposition(SIGTTIN), Disposition::Default);
1439 assert_eq!(process.disposition(SIGTTOU), Disposition::Default);
1440 })
1441 }
1442
1443 #[test]
1444 fn catching_signal() {
1445 let system = DummySystem::default();
1446 let mut trap_set = TrapSet::default();
1447 let command = Action::Command("echo INT".into());
1448 let origin = Location::dummy("origin");
1449 trap_set
1450 .set_action(&system, SIGINT, command, origin, false)
1451 .now_or_never()
1452 .unwrap()
1453 .unwrap();
1454 let command = Action::Command("echo TERM".into());
1455 let origin = Location::dummy("origin");
1456 trap_set
1457 .set_action(&system, SIGTERM, command, origin, false)
1458 .now_or_never()
1459 .unwrap()
1460 .unwrap();
1461
1462 trap_set.catch_signal(SIGCHLD);
1463 trap_set.catch_signal(SIGINT);
1464
1465 let trap_state = trap_set.get_state(SIGINT).0.unwrap();
1466 assert!(trap_state.pending, "trap_state = {trap_state:?}");
1467 let trap_state = trap_set.get_state(SIGTERM).0.unwrap();
1468 assert!(!trap_state.pending, "trap_state = {trap_state:?}");
1469 }
1470
1471 #[test]
1472 fn taking_signal_if_caught() {
1473 let system = DummySystem::default();
1474 let mut trap_set = TrapSet::default();
1475 let command = Action::Command("echo INT".into());
1476 let origin = Location::dummy("origin");
1477 trap_set
1478 .set_action(&system, SIGINT, command, origin, false)
1479 .now_or_never()
1480 .unwrap()
1481 .unwrap();
1482
1483 let result = trap_set.take_signal_if_caught(SIGINT);
1484 assert_eq!(result, None);
1485
1486 trap_set.catch_signal(SIGINT);
1487
1488 let result = trap_set.take_signal_if_caught(SIGINT);
1489 assert!(!result.unwrap().pending);
1490
1491 let result = trap_set.take_signal_if_caught(SIGINT);
1492 assert_eq!(result, None);
1493 }
1494
1495 #[test]
1496 fn taking_caught_signal() {
1497 let system = DummySystem::default();
1498 let mut trap_set = TrapSet::default();
1499 assert_eq!(trap_set.take_caught_signal(), None);
1500
1501 let command = Action::Command("echo INT".into());
1502 let origin = Location::dummy("origin");
1503 trap_set
1504 .set_action(&system, SIGINT, command, origin, false)
1505 .now_or_never()
1506 .unwrap()
1507 .unwrap();
1508 let command = Action::Command("echo TERM".into());
1509 let origin = Location::dummy("origin");
1510 trap_set
1511 .set_action(&system, SIGTERM, command, origin, false)
1512 .now_or_never()
1513 .unwrap()
1514 .unwrap();
1515 let command = Action::Command("echo USR1".into());
1516 let origin = Location::dummy("origin");
1517 trap_set
1518 .set_action(&system, SIGUSR1, command, origin, false)
1519 .now_or_never()
1520 .unwrap()
1521 .unwrap();
1522 assert_eq!(trap_set.take_caught_signal(), None);
1523
1524 trap_set.catch_signal(SIGINT);
1525 trap_set.catch_signal(SIGUSR1);
1526 let result = trap_set.take_caught_signal().unwrap();
1529 match result.0 {
1530 SIGINT => {
1531 assert_eq!(result.1.action, Action::Command("echo INT".into()));
1532 assert!(!result.1.pending);
1533
1534 let result = trap_set.take_caught_signal().unwrap();
1535 assert_eq!(result.0, SIGUSR1);
1536 assert_eq!(result.1.action, Action::Command("echo USR1".into()));
1537 assert!(!result.1.pending);
1538 }
1539 SIGUSR1 => {
1540 assert_eq!(result.1.action, Action::Command("echo USR1".into()));
1541 assert!(!result.1.pending);
1542
1543 let result = trap_set.take_caught_signal().unwrap();
1544 assert_eq!(result.0, SIGINT);
1545 assert_eq!(result.1.action, Action::Command("echo INT".into()));
1546 assert!(!result.1.pending);
1547 }
1548 _ => panic!("wrong signal: {result:?}"),
1549 }
1550
1551 assert_eq!(trap_set.take_caught_signal(), None);
1552 }
1553
1554 #[test]
1555 fn enabling_internal_disposition_for_sigchld() {
1556 let system = DummySystem::default();
1557 let mut trap_set = TrapSet::default();
1558 trap_set
1559 .enable_internal_disposition_for_sigchld(&system)
1560 .now_or_never()
1561 .unwrap()
1562 .unwrap();
1563 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Catch);
1564 }
1565
1566 #[test]
1567 fn enabling_internal_dispositions_for_terminators() {
1568 let system = DummySystem::default();
1569 let mut trap_set = TrapSet::default();
1570 trap_set
1571 .enable_internal_dispositions_for_terminators(&system)
1572 .now_or_never()
1573 .unwrap()
1574 .unwrap();
1575 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Catch);
1576 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Ignore);
1577 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1578 }
1579
1580 #[test]
1581 fn enabling_internal_dispositions_for_stoppers() {
1582 let system = DummySystem::default();
1583 let mut trap_set = TrapSet::default();
1584 trap_set
1585 .enable_internal_dispositions_for_stoppers(&system)
1586 .now_or_never()
1587 .unwrap()
1588 .unwrap();
1589 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Ignore);
1590 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Ignore);
1591 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Ignore);
1592 }
1593
1594 #[test]
1595 fn disabling_internal_dispositions_for_initially_defaulted_signals() {
1596 let system = DummySystem::default();
1597 let mut trap_set = TrapSet::default();
1598 trap_set
1599 .enable_internal_disposition_for_sigchld(&system)
1600 .now_or_never()
1601 .unwrap()
1602 .unwrap();
1603 trap_set
1604 .enable_internal_dispositions_for_terminators(&system)
1605 .now_or_never()
1606 .unwrap()
1607 .unwrap();
1608 trap_set
1609 .enable_internal_dispositions_for_stoppers(&system)
1610 .now_or_never()
1611 .unwrap()
1612 .unwrap();
1613 trap_set
1614 .disable_internal_dispositions(&system)
1615 .now_or_never()
1616 .unwrap()
1617 .unwrap();
1618 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Default);
1619 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Default);
1620 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Default);
1621 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Default);
1622 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Default);
1623 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Default);
1624 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Default);
1625 }
1626
1627 fn ignore_signals(system: &mut DummySystem) {
1628 system.0.borrow_mut().extend(
1629 [SIGCHLD, SIGINT, SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU]
1630 .into_iter()
1631 .map(|signal| (signal, Disposition::Ignore)),
1632 )
1633 }
1634
1635 #[test]
1636 fn disabling_internal_dispositions_for_initially_ignored_signals() {
1637 let mut system = DummySystem::default();
1638 ignore_signals(&mut system);
1639 let mut trap_set = TrapSet::default();
1640 trap_set
1641 .enable_internal_disposition_for_sigchld(&system)
1642 .now_or_never()
1643 .unwrap()
1644 .unwrap();
1645 trap_set
1646 .enable_internal_dispositions_for_terminators(&system)
1647 .now_or_never()
1648 .unwrap()
1649 .unwrap();
1650 trap_set
1651 .enable_internal_dispositions_for_stoppers(&system)
1652 .now_or_never()
1653 .unwrap()
1654 .unwrap();
1655 trap_set
1656 .disable_internal_dispositions(&system)
1657 .now_or_never()
1658 .unwrap()
1659 .unwrap();
1660 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Ignore);
1661 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Ignore);
1662 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Ignore);
1663 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1664 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Ignore);
1665 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Ignore);
1666 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Ignore);
1667 }
1668
1669 #[test]
1670 fn disabling_internal_dispositions_after_enabling_twice() {
1671 let mut system = DummySystem::default();
1672 ignore_signals(&mut system);
1673 let mut trap_set = TrapSet::default();
1674 trap_set
1675 .enable_internal_disposition_for_sigchld(&system)
1676 .now_or_never()
1677 .unwrap()
1678 .unwrap();
1679 trap_set
1680 .enable_internal_disposition_for_sigchld(&system)
1681 .now_or_never()
1682 .unwrap()
1683 .unwrap();
1684 trap_set
1685 .enable_internal_dispositions_for_terminators(&system)
1686 .now_or_never()
1687 .unwrap()
1688 .unwrap();
1689 trap_set
1690 .enable_internal_dispositions_for_terminators(&system)
1691 .now_or_never()
1692 .unwrap()
1693 .unwrap();
1694 trap_set
1695 .enable_internal_dispositions_for_stoppers(&system)
1696 .now_or_never()
1697 .unwrap()
1698 .unwrap();
1699 trap_set
1700 .enable_internal_dispositions_for_stoppers(&system)
1701 .now_or_never()
1702 .unwrap()
1703 .unwrap();
1704 trap_set
1705 .disable_internal_dispositions(&system)
1706 .now_or_never()
1707 .unwrap()
1708 .unwrap();
1709 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Ignore);
1710 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Ignore);
1711 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Ignore);
1712 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1713 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Ignore);
1714 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Ignore);
1715 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Ignore);
1716 }
1717
1718 #[test]
1719 fn disabling_internal_dispositions_without_enabling() {
1720 let mut system = DummySystem::default();
1721 ignore_signals(&mut system);
1722 let mut trap_set = TrapSet::default();
1723 trap_set
1724 .disable_internal_dispositions(&system)
1725 .now_or_never()
1726 .unwrap()
1727 .unwrap();
1728 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Ignore);
1729 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Ignore);
1730 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Ignore);
1731 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1732 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Ignore);
1733 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Ignore);
1734 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Ignore);
1735 }
1736
1737 #[test]
1738 fn reenabling_internal_dispositions() {
1739 let system = DummySystem::default();
1740 let mut trap_set = TrapSet::default();
1741 trap_set
1742 .enable_internal_disposition_for_sigchld(&system)
1743 .now_or_never()
1744 .unwrap()
1745 .unwrap();
1746 trap_set
1747 .enable_internal_disposition_for_sigchld(&system)
1748 .now_or_never()
1749 .unwrap()
1750 .unwrap();
1751 trap_set
1752 .enable_internal_dispositions_for_terminators(&system)
1753 .now_or_never()
1754 .unwrap()
1755 .unwrap();
1756 trap_set
1757 .enable_internal_dispositions_for_terminators(&system)
1758 .now_or_never()
1759 .unwrap()
1760 .unwrap();
1761 trap_set
1762 .enable_internal_dispositions_for_stoppers(&system)
1763 .now_or_never()
1764 .unwrap()
1765 .unwrap();
1766 trap_set
1767 .enable_internal_dispositions_for_stoppers(&system)
1768 .now_or_never()
1769 .unwrap()
1770 .unwrap();
1771 trap_set
1772 .disable_internal_dispositions(&system)
1773 .now_or_never()
1774 .unwrap()
1775 .unwrap();
1776 trap_set
1777 .enable_internal_disposition_for_sigchld(&system)
1778 .now_or_never()
1779 .unwrap()
1780 .unwrap();
1781 trap_set
1782 .enable_internal_dispositions_for_terminators(&system)
1783 .now_or_never()
1784 .unwrap()
1785 .unwrap();
1786 trap_set
1787 .enable_internal_dispositions_for_stoppers(&system)
1788 .now_or_never()
1789 .unwrap()
1790 .unwrap();
1791 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Catch);
1792 assert_eq!(system.0.borrow()[&SIGINT], Disposition::Catch);
1793 assert_eq!(system.0.borrow()[&SIGTERM], Disposition::Ignore);
1794 assert_eq!(system.0.borrow()[&SIGQUIT], Disposition::Ignore);
1795 assert_eq!(system.0.borrow()[&SIGTSTP], Disposition::Ignore);
1796 assert_eq!(system.0.borrow()[&SIGTTIN], Disposition::Ignore);
1797 assert_eq!(system.0.borrow()[&SIGTTOU], Disposition::Ignore);
1798 }
1799
1800 #[test]
1801 fn setting_trap_to_ignore_after_enabling_internal_disposition() {
1802 let system = DummySystem::default();
1803 let mut trap_set = TrapSet::default();
1804 trap_set
1805 .enable_internal_disposition_for_sigchld(&system)
1806 .now_or_never()
1807 .unwrap()
1808 .unwrap();
1809 let origin = Location::dummy("origin");
1810 let result = trap_set
1811 .set_action(&system, SIGCHLD, Action::Ignore, origin, false)
1812 .now_or_never()
1813 .unwrap();
1814 assert_eq!(result, Ok(()));
1815 assert_eq!(system.0.borrow()[&SIGCHLD], Disposition::Catch);
1816 }
1817
1818 #[test]
1819 fn resetting_trap_from_ignore_no_override_after_enabling_internal_dispositions() {
1820 let mut system = DummySystem::default();
1821 ignore_signals(&mut system);
1822 let mut trap_set = TrapSet::default();
1823 trap_set
1824 .enable_internal_disposition_for_sigchld(&system)
1825 .now_or_never()
1826 .unwrap()
1827 .unwrap();
1828 trap_set
1829 .enable_internal_dispositions_for_terminators(&system)
1830 .now_or_never()
1831 .unwrap()
1832 .unwrap();
1833 trap_set
1834 .enable_internal_dispositions_for_stoppers(&system)
1835 .now_or_never()
1836 .unwrap()
1837 .unwrap();
1838
1839 for signal in [SIGCHLD, SIGINT] {
1840 let origin = Location::dummy("origin");
1841 let result = trap_set
1842 .set_action(&system, signal, Action::Default, origin, false)
1843 .now_or_never()
1844 .unwrap();
1845 assert_eq!(result, Err(SetActionError::InitiallyIgnored));
1846 assert_eq!(system.0.borrow()[&signal], Disposition::Catch);
1847 }
1848 for signal in [SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU] {
1849 let origin = Location::dummy("origin");
1850 let result = trap_set
1851 .set_action(&system, signal, Action::Default, origin, false)
1852 .now_or_never()
1853 .unwrap();
1854 assert_eq!(result, Err(SetActionError::InitiallyIgnored));
1855 assert_eq!(system.0.borrow()[&signal], Disposition::Ignore);
1856 }
1857 }
1858
1859 #[test]
1860 fn resetting_trap_from_ignore_override_after_enabling_internal_dispositions() {
1861 let mut system = DummySystem::default();
1862 ignore_signals(&mut system);
1863 let mut trap_set = TrapSet::default();
1864 trap_set
1865 .enable_internal_disposition_for_sigchld(&system)
1866 .now_or_never()
1867 .unwrap()
1868 .unwrap();
1869 trap_set
1870 .enable_internal_dispositions_for_terminators(&system)
1871 .now_or_never()
1872 .unwrap()
1873 .unwrap();
1874 trap_set
1875 .enable_internal_dispositions_for_stoppers(&system)
1876 .now_or_never()
1877 .unwrap()
1878 .unwrap();
1879
1880 for signal in [SIGCHLD, SIGINT] {
1881 let origin = Location::dummy("origin");
1882 let result = trap_set
1883 .set_action(&system, signal, Action::Ignore, origin.clone(), true)
1884 .now_or_never()
1885 .unwrap();
1886 assert_eq!(result, Ok(()));
1887 assert_eq!(
1888 trap_set.get_state(signal),
1889 (
1890 Some(&TrapState {
1891 action: Action::Ignore,
1892 origin: Origin::User(origin),
1893 pending: false
1894 }),
1895 None
1896 )
1897 );
1898 assert_eq!(system.0.borrow()[&signal], Disposition::Catch);
1899 }
1900 for signal in [SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU] {
1901 let origin = Location::dummy("origin");
1902 let result = trap_set
1903 .set_action(&system, signal, Action::Ignore, origin.clone(), true)
1904 .now_or_never()
1905 .unwrap();
1906 assert_eq!(result, Ok(()));
1907 assert_eq!(
1908 trap_set.get_state(signal),
1909 (
1910 Some(&TrapState {
1911 action: Action::Ignore,
1912 origin: Origin::User(origin),
1913 pending: false
1914 }),
1915 None
1916 )
1917 );
1918 assert_eq!(system.0.borrow()[&signal], Disposition::Ignore);
1919 }
1920 }
1921
1922 #[test]
1923 fn disabling_internal_disposition_with_ignore_trap() {
1924 let signals = [SIGCHLD, SIGINT, SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU];
1925
1926 let system = DummySystem::default();
1927 let mut trap_set = TrapSet::default();
1928 trap_set
1929 .enable_internal_disposition_for_sigchld(&system)
1930 .now_or_never()
1931 .unwrap()
1932 .unwrap();
1933 trap_set
1934 .enable_internal_dispositions_for_terminators(&system)
1935 .now_or_never()
1936 .unwrap()
1937 .unwrap();
1938 let origin = Location::dummy("origin");
1939 for signal in signals {
1940 trap_set
1941 .set_action(&system, signal, Action::Ignore, origin.clone(), false)
1942 .now_or_never()
1943 .unwrap()
1944 .unwrap();
1945 }
1946 trap_set
1947 .disable_internal_dispositions(&system)
1948 .now_or_never()
1949 .unwrap()
1950 .unwrap();
1951
1952 for signal in signals {
1953 assert_eq!(
1954 trap_set.get_state(signal),
1955 (
1956 Some(&TrapState {
1957 action: Action::Ignore,
1958 origin: Origin::User(origin.clone()),
1959 pending: false
1960 }),
1961 None
1962 )
1963 );
1964 assert_eq!(system.0.borrow()[&signal], Disposition::Ignore);
1965 }
1966 }
1967}