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;
45use crate::system::{Disposition, Errno};
46#[cfg(doc)]
47use crate::system::{SharedSystem, System};
48use std::collections::BTreeMap;
49use std::collections::btree_map::Entry;
50use std::pin::Pin;
51
52pub trait SignalSystem {
54 #[must_use]
56 fn signal_name_from_number(&self, number: signal::Number) -> signal::Name;
57
58 #[must_use]
77 fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number>;
78
79 fn get_disposition(&self, signal: signal::Number) -> Result<Disposition, Errno>;
85
86 fn set_disposition(
91 &mut self,
92 signal: signal::Number,
93 disposition: Disposition,
94 ) -> Result<Disposition, Errno>;
95}
96
97#[must_use]
101pub struct Iter<'a> {
102 inner: std::collections::btree_map::Iter<'a, Condition, GrandState>,
103}
104
105impl<'a> Iterator for Iter<'a> {
106 type Item = (&'a Condition, &'a TrapState, Option<&'a TrapState>);
111
112 fn next(&mut self) -> Option<(&'a Condition, &'a TrapState, Option<&'a TrapState>)> {
113 self.inner
114 .next()
115 .map(|(cond, state)| (cond, state.current_state(), state.parent_state()))
116 }
117}
118
119#[derive(Clone, Debug, Default)]
123pub struct TrapSet {
124 traps: BTreeMap<Condition, GrandState>,
125}
126
127impl TrapSet {
128 pub fn get_state<C: Into<Condition>>(
144 &self,
145 cond: C,
146 ) -> (Option<&TrapState>, Option<&TrapState>) {
147 self.get_state_impl(cond.into())
148 }
149
150 fn get_state_impl(&self, cond: Condition) -> (Option<&TrapState>, Option<&TrapState>) {
151 match self.traps.get(&cond) {
152 None => (None, None),
153 Some(state) => (Some(state.current_state()), state.parent_state()),
154 }
155 }
156
157 pub fn peek_state<S: SignalSystem, C: Into<Condition>>(
175 &mut self,
176 system: &S,
177 cond: C,
178 ) -> Result<&TrapState, Errno> {
179 self.peek_state_impl(system, cond.into())
180 }
181
182 fn peek_state_impl<S: SignalSystem>(
183 &mut self,
184 system: &S,
185 cond: Condition,
186 ) -> Result<&TrapState, Errno> {
187 let entry = self.traps.entry(cond);
188 let state = GrandState::insert_from_system_if_vacant(system, entry)?;
189 Ok(state.parent_state().unwrap_or(state.current_state()))
190 }
191
192 pub fn set_action<S: SignalSystem, C: Into<Condition>>(
211 &mut self,
212 system: &mut S,
213 cond: C,
214 action: Action,
215 origin: Location,
216 override_ignore: bool,
217 ) -> Result<(), SetActionError> {
218 self.set_action_impl(system, cond.into(), action, origin, override_ignore)
219 }
220
221 fn set_action_impl<S: SignalSystem>(
222 &mut self,
223 system: &mut S,
224 cond: Condition,
225 action: Action,
226 origin: Location,
227 override_ignore: bool,
228 ) -> Result<(), SetActionError> {
229 if let Condition::Signal(number) = cond {
230 match system.signal_name_from_number(number) {
231 signal::Name::Kill => return Err(SetActionError::SIGKILL),
232 signal::Name::Stop => return Err(SetActionError::SIGSTOP),
233 _ => {}
234 }
235 }
236
237 self.clear_parent_states();
238
239 let entry = self.traps.entry(cond);
240 GrandState::set_action(system, entry, action, origin, override_ignore)
241 }
242
243 fn clear_parent_states(&mut self) {
244 for state in self.traps.values_mut() {
245 state.clear_parent_state();
246 }
247 }
248
249 #[inline]
261 pub fn iter(&self) -> Iter<'_> {
262 let inner = self.traps.iter();
263 Iter { inner }
264 }
265
266 pub fn enter_subshell<S: SignalSystem>(
302 &mut self,
303 system: &mut S,
304 ignore_sigint_sigquit: bool,
305 keep_internal_dispositions_for_stoppers: bool,
306 ) {
307 self.clear_parent_states();
308
309 for (&cond, state) in &mut self.traps {
310 let option = match cond {
311 Condition::Exit => EnterSubshellOption::ClearInternalDisposition,
312 Condition::Signal(number) => {
313 use signal::Name::*;
314 match system.signal_name_from_number(number) {
315 Chld => EnterSubshellOption::KeepInternalDisposition,
316 Int | Quit if ignore_sigint_sigquit => EnterSubshellOption::Ignore,
317 Tstp | Ttin | Ttou
318 if keep_internal_dispositions_for_stoppers
319 && state.internal_disposition() != Disposition::Default =>
320 {
321 EnterSubshellOption::Ignore
322 }
323 _ => EnterSubshellOption::ClearInternalDisposition,
324 }
325 }
326 };
327 _ = state.enter_subshell(system, cond, option);
328 }
329
330 if ignore_sigint_sigquit {
331 for name in [signal::Name::Int, signal::Name::Quit] {
332 let number = system
333 .signal_number_from_name(name)
334 .unwrap_or_else(|| panic!("missing support for signal {name}"));
335 match self.traps.entry(Condition::Signal(number)) {
336 Entry::Vacant(vacant) => _ = GrandState::ignore(system, vacant),
337 Entry::Occupied(_) => {}
339 }
340 }
341 }
342 }
343
344 pub fn catch_signal(&mut self, signal: signal::Number) {
349 if let Some(state) = self.traps.get_mut(&Condition::Signal(signal)) {
350 state.mark_as_caught();
351 }
352 }
353
354 pub fn take_signal_if_caught(&mut self, signal: signal::Number) -> Option<&TrapState> {
358 self.traps
359 .get_mut(&signal.into())
360 .and_then(|state| state.handle_if_caught())
361 }
362
363 pub fn take_caught_signal(&mut self) -> Option<(signal::Number, &TrapState)> {
371 self.traps.iter_mut().find_map(|(&cond, state)| match cond {
372 Condition::Signal(signal) => state.handle_if_caught().map(|trap| (signal, trap)),
373 _ => None,
374 })
375 }
376
377 fn set_internal_disposition<S: SignalSystem>(
378 &mut self,
379 signal: signal::Name,
380 disposition: Disposition,
381 system: &mut S,
382 ) -> Result<(), Errno> {
383 let number = system
384 .signal_number_from_name(signal)
385 .unwrap_or_else(|| panic!("missing support for signal {signal}"));
386 let entry = self.traps.entry(Condition::Signal(number));
387 GrandState::set_internal_disposition(system, entry, disposition)
388 }
389
390 pub fn enable_internal_disposition_for_sigchld<S: SignalSystem>(
400 &mut self,
401 system: &mut S,
402 ) -> Result<(), Errno> {
403 self.set_internal_disposition(signal::Name::Chld, Disposition::Catch, system)
404 }
405
406 pub fn enable_internal_dispositions_for_terminators<S: SignalSystem>(
415 &mut self,
416 system: &mut S,
417 ) -> Result<(), Errno> {
418 self.set_internal_disposition(signal::Name::Int, Disposition::Catch, system)?;
419 self.set_internal_disposition(signal::Name::Term, Disposition::Ignore, system)?;
420 self.set_internal_disposition(signal::Name::Quit, Disposition::Ignore, system)
421 }
422
423 pub fn enable_internal_dispositions_for_stoppers<S: SignalSystem>(
432 &mut self,
433 system: &mut S,
434 ) -> Result<(), Errno> {
435 self.set_internal_disposition(signal::Name::Tstp, Disposition::Ignore, system)?;
436 self.set_internal_disposition(signal::Name::Ttin, Disposition::Ignore, system)?;
437 self.set_internal_disposition(signal::Name::Ttou, Disposition::Ignore, system)
438 }
439
440 pub fn disable_internal_dispositions_for_terminators<S: SignalSystem>(
442 &mut self,
443 system: &mut S,
444 ) -> Result<(), Errno> {
445 self.set_internal_disposition(signal::Name::Int, Disposition::Default, system)?;
446 self.set_internal_disposition(signal::Name::Term, Disposition::Default, system)?;
447 self.set_internal_disposition(signal::Name::Quit, Disposition::Default, system)
448 }
449
450 pub fn disable_internal_dispositions_for_stoppers<S: SignalSystem>(
452 &mut self,
453 system: &mut S,
454 ) -> Result<(), Errno> {
455 self.set_internal_disposition(signal::Name::Tstp, Disposition::Default, system)?;
456 self.set_internal_disposition(signal::Name::Ttin, Disposition::Default, system)?;
457 self.set_internal_disposition(signal::Name::Ttou, Disposition::Default, system)
458 }
459
460 pub fn disable_internal_dispositions<S: SignalSystem>(
466 &mut self,
467 system: &mut S,
468 ) -> Result<(), Errno> {
469 self.set_internal_disposition(signal::Name::Chld, Disposition::Default, system)?;
470 self.disable_internal_dispositions_for_terminators(system)?;
471 self.disable_internal_dispositions_for_stoppers(system)
472 }
473}
474
475impl<'a> IntoIterator for &'a TrapSet {
476 type Item = (&'a Condition, &'a TrapState, Option<&'a TrapState>);
481 type IntoIter = Iter<'a>;
482
483 #[inline(always)]
484 fn into_iter(self) -> Iter<'a> {
485 self.iter()
486 }
487}
488
489type PinFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
490
491pub struct RunSignalTrapIfCaught<S>(
518 pub for<'a> fn(
519 env: &'a mut Env<S>,
520 signal: signal::Number,
521 ) -> PinFuture<'a, Option<crate::semantics::Result>>,
522);
523
524impl<S> Clone for RunSignalTrapIfCaught<S> {
526 fn clone(&self) -> Self {
527 *self
528 }
529}
530
531impl<S> Copy for RunSignalTrapIfCaught<S> {}
532
533impl<S> std::fmt::Debug for RunSignalTrapIfCaught<S> {
534 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
535 f.debug_tuple("RunSignalTrapIfCaught")
536 .field(&self.0)
537 .finish()
538 }
539}
540
541#[cfg(test)]
542mod tests {
543 use super::*;
544 use crate::job::ProcessState;
545 use crate::system::SendSignal as _;
546 use crate::system::Signals as _;
547 use crate::system::r#virtual::VirtualSystem;
548 use crate::system::r#virtual::{
549 SIGCHLD, SIGINT, SIGKILL, SIGQUIT, SIGSTOP, SIGTERM, SIGTSTP, SIGTTIN, SIGTTOU, SIGUSR1,
550 SIGUSR2,
551 };
552 use crate::tests::in_virtual_system;
553 use std::collections::HashMap;
554
555 #[derive(Default)]
556 pub struct DummySystem(pub HashMap<signal::Number, Disposition>);
557
558 impl SignalSystem for DummySystem {
559 fn signal_name_from_number(&self, number: signal::Number) -> signal::Name {
560 VirtualSystem::new().signal_name_from_number(number)
561 }
562
563 fn signal_number_from_name(&self, name: signal::Name) -> Option<signal::Number> {
564 VirtualSystem::new().signal_number_from_name(name)
565 }
566
567 fn get_disposition(&self, signal: signal::Number) -> Result<Disposition, Errno> {
568 Ok(self.0.get(&signal).copied().unwrap_or_default())
569 }
570
571 fn set_disposition(
572 &mut self,
573 signal: signal::Number,
574 disposition: Disposition,
575 ) -> Result<Disposition, Errno> {
576 Ok(self.0.insert(signal, disposition).unwrap_or_default())
577 }
578 }
579
580 #[test]
581 fn default_trap() {
582 let trap_set = TrapSet::default();
583 assert_eq!(trap_set.get_state(SIGCHLD), (None, None));
584 }
585
586 #[test]
587 fn setting_trap_for_two_signals() {
588 let mut system = DummySystem::default();
589 let mut trap_set = TrapSet::default();
590 let origin_1 = Location::dummy("foo");
591 let result = trap_set.set_action(
592 &mut system,
593 SIGUSR1,
594 Action::Ignore,
595 origin_1.clone(),
596 false,
597 );
598 assert_eq!(result, Ok(()));
599
600 let command = Action::Command("echo".into());
601 let origin_2 = Location::dummy("bar");
602 let result = trap_set.set_action(
603 &mut system,
604 SIGUSR2,
605 command.clone(),
606 origin_2.clone(),
607 false,
608 );
609 assert_eq!(result, Ok(()));
610
611 assert_eq!(
612 trap_set.get_state(SIGUSR1),
613 (
614 Some(&TrapState {
615 action: Action::Ignore,
616 origin: Origin::User(origin_1),
617 pending: false
618 }),
619 None
620 )
621 );
622 assert_eq!(
623 trap_set.get_state(SIGUSR2),
624 (
625 Some(&TrapState {
626 action: command,
627 origin: Origin::User(origin_2),
628 pending: false
629 }),
630 None
631 )
632 );
633 assert_eq!(system.0[&SIGUSR1], Disposition::Ignore);
634 assert_eq!(system.0[&SIGUSR2], Disposition::Catch);
635 }
636
637 #[test]
638 fn setting_trap_for_sigkill() {
639 let mut system = DummySystem::default();
640 let mut trap_set = TrapSet::default();
641 let origin = Location::dummy("origin");
642 let result = trap_set.set_action(&mut system, SIGKILL, Action::Ignore, origin, false);
643 assert_eq!(result, Err(SetActionError::SIGKILL));
644 assert_eq!(trap_set.get_state(SIGKILL), (None, None));
645 assert_eq!(system.0.get(&SIGKILL), None);
646 }
647
648 #[test]
649 fn setting_trap_for_sigstop() {
650 let mut system = DummySystem::default();
651 let mut trap_set = TrapSet::default();
652 let origin = Location::dummy("origin");
653 let result = trap_set.set_action(&mut system, SIGSTOP, Action::Ignore, origin, false);
654 assert_eq!(result, Err(SetActionError::SIGSTOP));
655 assert_eq!(trap_set.get_state(SIGSTOP), (None, None));
656 assert_eq!(system.0.get(&SIGSTOP), None);
657 }
658
659 #[test]
660 fn peeking_state_with_default_inherited_disposition() {
661 let system = DummySystem::default();
662 let mut trap_set = TrapSet::default();
663 let result = trap_set.peek_state(&system, SIGCHLD);
664 assert_eq!(
665 result,
666 Ok(&TrapState {
667 action: Action::Default,
668 origin: Origin::Inherited,
669 pending: false
670 })
671 );
672 }
673
674 #[test]
675 fn peeking_state_with_inherited_disposition_of_ignore() {
676 let mut system = DummySystem::default();
677 system.0.insert(SIGCHLD, Disposition::Ignore);
678 let mut trap_set = TrapSet::default();
679 let result = trap_set.peek_state(&system, SIGCHLD);
680 assert_eq!(
681 result,
682 Ok(&TrapState {
683 action: Action::Ignore,
684 origin: Origin::Inherited,
685 pending: false
686 })
687 );
688 }
689
690 #[test]
691 fn peeking_state_with_parent_state() {
692 let mut system = DummySystem::default();
693 let mut trap_set = TrapSet::default();
694 let origin = Location::dummy("foo");
695 let command = Action::Command("echo".into());
696 trap_set
697 .set_action(&mut system, SIGUSR1, command.clone(), origin.clone(), false)
698 .unwrap();
699 trap_set.enter_subshell(&mut system, false, false);
700
701 let result = trap_set.peek_state(&system, SIGUSR1);
702 assert_eq!(
703 result,
704 Ok(&TrapState {
705 action: command,
706 origin: Origin::User(origin),
707 pending: false
708 })
709 );
710 }
711
712 #[test]
713 fn basic_iteration() {
714 let mut system = DummySystem::default();
715 let mut trap_set = TrapSet::default();
716 let origin_1 = Location::dummy("foo");
717 trap_set
718 .set_action(
719 &mut system,
720 SIGUSR1,
721 Action::Ignore,
722 origin_1.clone(),
723 false,
724 )
725 .unwrap();
726 let command = Action::Command("echo".into());
727 let origin_2 = Location::dummy("bar");
728 trap_set
729 .set_action(
730 &mut system,
731 SIGUSR2,
732 command.clone(),
733 origin_2.clone(),
734 false,
735 )
736 .unwrap();
737
738 let mut i = trap_set.iter();
739 let first = i.next().unwrap();
740 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
741 assert_eq!(first.1.action, Action::Ignore);
742 assert_eq!(first.1.origin, Origin::User(origin_1));
743 assert_eq!(first.2, None);
744 let second = i.next().unwrap();
745 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
746 assert_eq!(second.1.action, command);
747 assert_eq!(second.1.origin, Origin::User(origin_2));
748 assert_eq!(first.2, None);
749 assert_eq!(i.next(), None);
750 }
751
752 #[test]
753 fn iteration_after_entering_subshell() {
754 let mut system = DummySystem::default();
755 let mut trap_set = TrapSet::default();
756 let origin_1 = Location::dummy("foo");
757 trap_set
758 .set_action(
759 &mut system,
760 SIGUSR1,
761 Action::Ignore,
762 origin_1.clone(),
763 false,
764 )
765 .unwrap();
766 let command = Action::Command("echo".into());
767 let origin_2 = Location::dummy("bar");
768 trap_set
769 .set_action(
770 &mut system,
771 SIGUSR2,
772 command.clone(),
773 origin_2.clone(),
774 false,
775 )
776 .unwrap();
777 trap_set.enter_subshell(&mut system, false, false);
778
779 let mut i = trap_set.iter();
780 let first = i.next().unwrap();
781 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
782 assert_eq!(first.1.action, Action::Ignore);
783 assert_eq!(first.1.origin, Origin::User(origin_1));
784 assert_eq!(first.2, None);
785 let second = i.next().unwrap();
786 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
787 assert_eq!(second.1.action, Action::Default);
788 assert_eq!(second.1.origin, Origin::Subshell);
789 assert_eq!(second.2.unwrap().action, command);
790 assert_eq!(second.2.unwrap().origin, Origin::User(origin_2));
791 assert_eq!(i.next(), None);
792 }
793
794 #[test]
795 fn iteration_after_setting_trap_in_subshell() {
796 let mut system = DummySystem::default();
797 let mut trap_set = TrapSet::default();
798 let origin_1 = Location::dummy("foo");
799 let command = Action::Command("echo".into());
800 trap_set
801 .set_action(&mut system, SIGUSR1, command, origin_1, false)
802 .unwrap();
803 trap_set.enter_subshell(&mut system, false, false);
804 let origin_2 = Location::dummy("bar");
805 let command = Action::Command("ls".into());
806 trap_set
807 .set_action(
808 &mut system,
809 SIGUSR2,
810 command.clone(),
811 origin_2.clone(),
812 false,
813 )
814 .unwrap();
815
816 let mut i = trap_set.iter();
817 let first = i.next().unwrap();
818 assert_eq!(first.0, &Condition::Signal(SIGUSR1));
819 assert_eq!(first.1.action, Action::Default);
820 assert_eq!(first.1.origin, Origin::Subshell);
821 assert_eq!(first.2, None);
822 let second = i.next().unwrap();
823 assert_eq!(second.0, &Condition::Signal(SIGUSR2));
824 assert_eq!(second.1.action, command);
825 assert_eq!(second.1.origin, Origin::User(origin_2));
826 assert_eq!(second.2, None);
827 assert_eq!(i.next(), None);
828 }
829
830 #[test]
831 fn entering_subshell_resets_command_traps() {
832 let mut system = DummySystem::default();
833 let mut trap_set = TrapSet::default();
834 let action = Action::Command("".into());
835 let origin = Location::dummy("origin");
836 trap_set
837 .set_action(&mut system, SIGCHLD, action.clone(), origin.clone(), false)
838 .unwrap();
839
840 trap_set.enter_subshell(&mut system, false, false);
841 assert_eq!(
842 trap_set.get_state(SIGCHLD),
843 (
844 Some(&TrapState {
845 action: Action::Default,
846 origin: Origin::Subshell,
847 pending: false
848 }),
849 Some(&TrapState {
850 action,
851 origin: Origin::User(origin),
852 pending: false
853 })
854 )
855 );
856 assert_eq!(system.0[&SIGCHLD], Disposition::Default);
857 }
858
859 #[test]
860 fn entering_subshell_keeps_ignore_traps() {
861 let mut system = DummySystem::default();
862 let mut trap_set = TrapSet::default();
863 let origin = Location::dummy("origin");
864 trap_set
865 .set_action(&mut system, SIGCHLD, Action::Ignore, origin.clone(), false)
866 .unwrap();
867
868 trap_set.enter_subshell(&mut system, false, false);
869 assert_eq!(
870 trap_set.get_state(SIGCHLD),
871 (
872 Some(&TrapState {
873 action: Action::Ignore,
874 origin: Origin::User(origin),
875 pending: false
876 }),
877 None
878 )
879 );
880 assert_eq!(system.0[&SIGCHLD], Disposition::Ignore);
881 }
882
883 #[test]
884 fn entering_subshell_with_internal_disposition_for_sigchld() {
885 let mut system = DummySystem::default();
886 let mut trap_set = TrapSet::default();
887 let action = Action::Command("".into());
888 let origin = Location::dummy("origin");
889 trap_set
890 .set_action(&mut system, SIGCHLD, action.clone(), origin.clone(), false)
891 .unwrap();
892 trap_set
893 .enable_internal_disposition_for_sigchld(&mut system)
894 .unwrap();
895
896 trap_set.enter_subshell(&mut system, false, false);
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[&SIGCHLD], Disposition::Catch);
913 }
914
915 #[test]
916 fn entering_subshell_with_internal_disposition_for_sigint() {
917 let mut system = DummySystem::default();
918 let mut trap_set = TrapSet::default();
919 let action = Action::Command("".into());
920 let origin = Location::dummy("origin");
921 trap_set
922 .set_action(&mut system, SIGINT, action.clone(), origin.clone(), false)
923 .unwrap();
924 trap_set
925 .enable_internal_dispositions_for_terminators(&mut system)
926 .unwrap();
927
928 trap_set.enter_subshell(&mut system, false, false);
929 assert_eq!(
930 trap_set.get_state(SIGINT),
931 (
932 Some(&TrapState {
933 action: Action::Default,
934 origin: Origin::Subshell,
935 pending: false
936 }),
937 Some(&TrapState {
938 action,
939 origin: Origin::User(origin),
940 pending: false
941 })
942 )
943 );
944 assert_eq!(system.0[&SIGINT], Disposition::Default);
945 }
946
947 #[test]
948 fn entering_subshell_with_internal_disposition_for_sigterm() {
949 let mut system = DummySystem::default();
950 let mut trap_set = TrapSet::default();
951 let action = Action::Command("".into());
952 let origin = Location::dummy("origin");
953 trap_set
954 .set_action(&mut system, SIGTERM, action.clone(), origin.clone(), false)
955 .unwrap();
956 trap_set
957 .enable_internal_dispositions_for_terminators(&mut system)
958 .unwrap();
959
960 trap_set.enter_subshell(&mut system, false, false);
961 assert_eq!(
962 trap_set.get_state(SIGTERM),
963 (
964 Some(&TrapState {
965 action: Action::Default,
966 origin: Origin::Subshell,
967 pending: false
968 }),
969 Some(&TrapState {
970 action,
971 origin: Origin::User(origin),
972 pending: false
973 })
974 )
975 );
976 assert_eq!(system.0[&SIGTERM], Disposition::Default);
977 }
978
979 #[test]
980 fn entering_subshell_with_internal_disposition_for_sigquit() {
981 let mut system = DummySystem::default();
982 let mut trap_set = TrapSet::default();
983 let action = Action::Command("".into());
984 let origin = Location::dummy("origin");
985 trap_set
986 .set_action(&mut system, SIGQUIT, action.clone(), origin.clone(), false)
987 .unwrap();
988 trap_set
989 .enable_internal_dispositions_for_terminators(&mut system)
990 .unwrap();
991
992 trap_set.enter_subshell(&mut system, false, false);
993 assert_eq!(
994 trap_set.get_state(SIGQUIT),
995 (
996 Some(&TrapState {
997 action: Action::Default,
998 origin: Origin::Subshell,
999 pending: false
1000 }),
1001 Some(&TrapState {
1002 action,
1003 origin: Origin::User(origin),
1004 pending: false
1005 })
1006 )
1007 );
1008 assert_eq!(system.0[&SIGQUIT], Disposition::Default);
1009 }
1010
1011 #[test]
1012 fn entering_subshell_with_internal_disposition_for_sigtstp() {
1013 let mut system = DummySystem::default();
1014 let mut trap_set = TrapSet::default();
1015 let action = Action::Command("".into());
1016 let origin = Location::dummy("origin");
1017 trap_set
1018 .set_action(&mut system, SIGTSTP, action.clone(), origin.clone(), false)
1019 .unwrap();
1020 trap_set
1021 .enable_internal_dispositions_for_terminators(&mut system)
1022 .unwrap();
1023
1024 trap_set.enter_subshell(&mut system, false, false);
1025 assert_eq!(
1026 trap_set.get_state(SIGTSTP),
1027 (
1028 Some(&TrapState {
1029 action: Action::Default,
1030 origin: Origin::Subshell,
1031 pending: false
1032 }),
1033 Some(&TrapState {
1034 action,
1035 origin: Origin::User(origin),
1036 pending: false
1037 })
1038 )
1039 );
1040 assert_eq!(system.0[&SIGTSTP], Disposition::Default);
1041 }
1042
1043 #[test]
1044 fn entering_subshell_with_internal_disposition_for_sigttin() {
1045 let mut system = DummySystem::default();
1046 let mut trap_set = TrapSet::default();
1047 let action = Action::Command("".into());
1048 let origin = Location::dummy("origin");
1049 trap_set
1050 .set_action(&mut system, SIGTTIN, action.clone(), origin.clone(), false)
1051 .unwrap();
1052 trap_set
1053 .enable_internal_dispositions_for_terminators(&mut system)
1054 .unwrap();
1055
1056 trap_set.enter_subshell(&mut system, false, false);
1057 assert_eq!(
1058 trap_set.get_state(SIGTTIN),
1059 (
1060 Some(&TrapState {
1061 action: Action::Default,
1062 origin: Origin::Subshell,
1063 pending: false
1064 }),
1065 Some(&TrapState {
1066 action,
1067 origin: Origin::User(origin),
1068 pending: false
1069 })
1070 )
1071 );
1072 assert_eq!(system.0[&SIGTTIN], Disposition::Default);
1073 }
1074
1075 #[test]
1076 fn entering_subshell_with_internal_disposition_for_sigttou() {
1077 let mut system = DummySystem::default();
1078 let mut trap_set = TrapSet::default();
1079 let action = Action::Command("".into());
1080 let origin = Location::dummy("origin");
1081 trap_set
1082 .set_action(&mut system, SIGTTOU, action.clone(), origin.clone(), false)
1083 .unwrap();
1084 trap_set
1085 .enable_internal_dispositions_for_terminators(&mut system)
1086 .unwrap();
1087
1088 trap_set.enter_subshell(&mut system, false, false);
1089 assert_eq!(
1090 trap_set.get_state(SIGTTOU),
1091 (
1092 Some(&TrapState {
1093 action: Action::Default,
1094 origin: Origin::Subshell,
1095 pending: false
1096 }),
1097 Some(&TrapState {
1098 action,
1099 origin: Origin::User(origin),
1100 pending: false
1101 })
1102 )
1103 );
1104 assert_eq!(system.0[&SIGTTOU], Disposition::Default);
1105 }
1106
1107 #[test]
1108 fn setting_trap_after_entering_subshell_clears_parent_states() {
1109 let mut system = DummySystem::default();
1110 let mut trap_set = TrapSet::default();
1111 let origin_1 = Location::dummy("foo");
1112 let command = Action::Command("echo 1".into());
1113 trap_set
1114 .set_action(&mut system, SIGUSR1, command, origin_1, false)
1115 .unwrap();
1116 let origin_2 = Location::dummy("bar");
1117 let command = Action::Command("echo 2".into());
1118 trap_set
1119 .set_action(&mut system, SIGUSR2, command, origin_2, false)
1120 .unwrap();
1121 trap_set.enter_subshell(&mut system, false, false);
1122
1123 let command = Action::Command("echo 9".into());
1124 let origin_3 = Location::dummy("qux");
1125 trap_set
1126 .set_action(
1127 &mut system,
1128 SIGUSR1,
1129 command.clone(),
1130 origin_3.clone(),
1131 false,
1132 )
1133 .unwrap();
1134
1135 assert_eq!(
1136 trap_set.get_state(SIGUSR1),
1137 (
1138 Some(&TrapState {
1139 action: command,
1140 origin: Origin::User(origin_3),
1141 pending: false
1142 }),
1143 None
1144 )
1145 );
1146 assert_eq!(
1147 trap_set.get_state(SIGUSR2),
1148 (
1149 Some(&TrapState {
1150 action: Action::Default,
1151 origin: Origin::Subshell,
1152 pending: false
1153 }),
1154 None
1155 )
1156 );
1157 assert_eq!(system.0[&SIGUSR1], Disposition::Catch);
1158 assert_eq!(system.0[&SIGUSR2], Disposition::Default);
1159 }
1160
1161 #[test]
1162 fn entering_nested_subshell_clears_parent_states() {
1163 let mut system = DummySystem::default();
1164 let mut trap_set = TrapSet::default();
1165 let origin_1 = Location::dummy("foo");
1166 let command = Action::Command("echo 1".into());
1167 trap_set
1168 .set_action(&mut system, SIGUSR1, command, origin_1, false)
1169 .unwrap();
1170 let origin_2 = Location::dummy("bar");
1171 let command = Action::Command("echo 2".into());
1172 trap_set
1173 .set_action(&mut system, SIGUSR2, command, origin_2, false)
1174 .unwrap();
1175 trap_set.enter_subshell(&mut system, false, false);
1176 trap_set.enter_subshell(&mut system, false, false);
1177
1178 assert_eq!(
1179 trap_set.get_state(SIGUSR1),
1180 (
1181 Some(&TrapState {
1182 action: Action::Default,
1183 origin: Origin::Subshell,
1184 pending: false
1185 }),
1186 None
1187 )
1188 );
1189 assert_eq!(
1190 trap_set.get_state(SIGUSR2),
1191 (
1192 Some(&TrapState {
1193 action: Action::Default,
1194 origin: Origin::Subshell,
1195 pending: false
1196 }),
1197 None
1198 )
1199 );
1200 assert_eq!(system.0[&SIGUSR1], Disposition::Default);
1201 assert_eq!(system.0[&SIGUSR2], Disposition::Default);
1202 }
1203
1204 #[test]
1205 fn ignoring_sigint_on_entering_subshell_with_action_set() {
1206 in_virtual_system(|mut env, state| async move {
1207 env.traps
1208 .set_action(
1209 &mut env.system,
1210 SIGINT,
1211 Action::Command("".into()),
1212 Location::dummy(""),
1213 false,
1214 )
1215 .unwrap();
1216 env.system.kill(env.main_pid, Some(SIGINT)).await.unwrap();
1217 env.traps.enter_subshell(&mut env.system, true, false);
1218
1219 let state = state.borrow();
1220 let process = &state.processes[&env.main_pid];
1221 assert_eq!(process.disposition(SIGINT), Disposition::Ignore);
1222 assert_eq!(process.state(), ProcessState::Running);
1223 })
1224 }
1225
1226 #[test]
1227 fn ignoring_sigquit_on_entering_subshell_with_action_set() {
1228 in_virtual_system(|mut env, state| async move {
1229 env.traps
1230 .set_action(
1231 &mut env.system,
1232 SIGQUIT,
1233 Action::Command("".into()),
1234 Location::dummy(""),
1235 false,
1236 )
1237 .unwrap();
1238 env.system.kill(env.main_pid, Some(SIGQUIT)).await.unwrap();
1239 env.traps.enter_subshell(&mut env.system, true, false);
1240
1241 let state = state.borrow();
1242 let process = &state.processes[&env.main_pid];
1243 assert_eq!(process.disposition(SIGQUIT), Disposition::Ignore);
1244 assert_eq!(process.state(), ProcessState::Running);
1245 })
1246 }
1247
1248 #[test]
1249 fn ignoring_sigint_and_sigquit_on_entering_subshell_without_action_set() {
1250 let mut system = DummySystem::default();
1251 let mut trap_set = TrapSet::default();
1252 trap_set.enter_subshell(&mut system, true, false);
1253 assert_eq!(system.0[&SIGINT], Disposition::Ignore);
1254 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1255 }
1256
1257 #[test]
1258 fn keeping_stopper_internal_dispositions_ignored() {
1259 in_virtual_system(|mut env, state| async move {
1260 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1261 env.traps
1262 .set_action(
1263 &mut env.system,
1264 signal,
1265 Action::Command("".into()),
1266 Location::dummy(""),
1267 false,
1268 )
1269 .unwrap();
1270 }
1271 env.traps
1272 .enable_internal_dispositions_for_stoppers(&mut env.system)
1273 .unwrap();
1274 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1275 env.system.kill(env.main_pid, Some(signal)).await.unwrap();
1276 }
1277 env.traps.enter_subshell(&mut env.system, false, true);
1278
1279 let state = state.borrow();
1280 let process = &state.processes[&env.main_pid];
1281 assert_eq!(process.disposition(SIGTSTP), Disposition::Ignore);
1282 assert_eq!(process.disposition(SIGTTIN), Disposition::Ignore);
1283 assert_eq!(process.disposition(SIGTTOU), Disposition::Ignore);
1284 assert_eq!(process.state(), ProcessState::Running);
1285 })
1286 }
1287
1288 #[test]
1289 fn no_stopper_internal_dispositions_enabled_to_be_kept_ignored() {
1290 in_virtual_system(|mut env, state| async move {
1291 for signal in [SIGTSTP, SIGTTIN, SIGTTOU] {
1292 env.traps
1293 .set_action(
1294 &mut env.system,
1295 signal,
1296 Action::Command("".into()),
1297 Location::dummy(""),
1298 false,
1299 )
1300 .unwrap();
1301 }
1302 env.traps.enter_subshell(&mut env.system, false, true);
1303
1304 let state = state.borrow();
1305 let process = &state.processes[&env.main_pid];
1306 assert_eq!(process.disposition(SIGTSTP), Disposition::Default);
1307 assert_eq!(process.disposition(SIGTTIN), Disposition::Default);
1308 assert_eq!(process.disposition(SIGTTOU), Disposition::Default);
1309 })
1310 }
1311
1312 #[test]
1313 fn catching_signal() {
1314 let mut system = DummySystem::default();
1315 let mut trap_set = TrapSet::default();
1316 let command = Action::Command("echo INT".into());
1317 let origin = Location::dummy("origin");
1318 trap_set
1319 .set_action(&mut system, SIGINT, command, origin, false)
1320 .unwrap();
1321 let command = Action::Command("echo TERM".into());
1322 let origin = Location::dummy("origin");
1323 trap_set
1324 .set_action(&mut system, SIGTERM, command, origin, false)
1325 .unwrap();
1326
1327 trap_set.catch_signal(SIGCHLD);
1328 trap_set.catch_signal(SIGINT);
1329
1330 let trap_state = trap_set.get_state(SIGINT).0.unwrap();
1331 assert!(trap_state.pending, "trap_state = {trap_state:?}");
1332 let trap_state = trap_set.get_state(SIGTERM).0.unwrap();
1333 assert!(!trap_state.pending, "trap_state = {trap_state:?}");
1334 }
1335
1336 #[test]
1337 fn taking_signal_if_caught() {
1338 let mut system = DummySystem::default();
1339 let mut trap_set = TrapSet::default();
1340 let command = Action::Command("echo INT".into());
1341 let origin = Location::dummy("origin");
1342 trap_set
1343 .set_action(&mut system, SIGINT, command, origin, false)
1344 .unwrap();
1345
1346 let result = trap_set.take_signal_if_caught(SIGINT);
1347 assert_eq!(result, None);
1348
1349 trap_set.catch_signal(SIGINT);
1350
1351 let result = trap_set.take_signal_if_caught(SIGINT);
1352 assert!(!result.unwrap().pending);
1353
1354 let result = trap_set.take_signal_if_caught(SIGINT);
1355 assert_eq!(result, None);
1356 }
1357
1358 #[test]
1359 fn taking_caught_signal() {
1360 let mut system = DummySystem::default();
1361 let mut trap_set = TrapSet::default();
1362 assert_eq!(trap_set.take_caught_signal(), None);
1363
1364 let command = Action::Command("echo INT".into());
1365 let origin = Location::dummy("origin");
1366 trap_set
1367 .set_action(&mut system, SIGINT, command, origin, false)
1368 .unwrap();
1369 let command = Action::Command("echo TERM".into());
1370 let origin = Location::dummy("origin");
1371 trap_set
1372 .set_action(&mut system, SIGTERM, command, origin, false)
1373 .unwrap();
1374 let command = Action::Command("echo USR1".into());
1375 let origin = Location::dummy("origin");
1376 trap_set
1377 .set_action(&mut system, SIGUSR1, command, origin, false)
1378 .unwrap();
1379 assert_eq!(trap_set.take_caught_signal(), None);
1380
1381 trap_set.catch_signal(SIGINT);
1382 trap_set.catch_signal(SIGUSR1);
1383 let result = trap_set.take_caught_signal().unwrap();
1386 match result.0 {
1387 SIGINT => {
1388 assert_eq!(result.1.action, Action::Command("echo INT".into()));
1389 assert!(!result.1.pending);
1390
1391 let result = trap_set.take_caught_signal().unwrap();
1392 assert_eq!(result.0, SIGUSR1);
1393 assert_eq!(result.1.action, Action::Command("echo USR1".into()));
1394 assert!(!result.1.pending);
1395 }
1396 SIGUSR1 => {
1397 assert_eq!(result.1.action, Action::Command("echo USR1".into()));
1398 assert!(!result.1.pending);
1399
1400 let result = trap_set.take_caught_signal().unwrap();
1401 assert_eq!(result.0, SIGINT);
1402 assert_eq!(result.1.action, Action::Command("echo INT".into()));
1403 assert!(!result.1.pending);
1404 }
1405 _ => panic!("wrong signal: {result:?}"),
1406 }
1407
1408 assert_eq!(trap_set.take_caught_signal(), None);
1409 }
1410
1411 #[test]
1412 fn enabling_internal_disposition_for_sigchld() {
1413 let mut system = DummySystem::default();
1414 let mut trap_set = TrapSet::default();
1415 trap_set
1416 .enable_internal_disposition_for_sigchld(&mut system)
1417 .unwrap();
1418 assert_eq!(system.0[&SIGCHLD], Disposition::Catch);
1419 }
1420
1421 #[test]
1422 fn enabling_internal_dispositions_for_terminators() {
1423 let mut system = DummySystem::default();
1424 let mut trap_set = TrapSet::default();
1425 trap_set
1426 .enable_internal_dispositions_for_terminators(&mut system)
1427 .unwrap();
1428 assert_eq!(system.0[&SIGINT], Disposition::Catch);
1429 assert_eq!(system.0[&SIGTERM], Disposition::Ignore);
1430 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1431 }
1432
1433 #[test]
1434 fn enabling_internal_dispositions_for_stoppers() {
1435 let mut system = DummySystem::default();
1436 let mut trap_set = TrapSet::default();
1437 trap_set
1438 .enable_internal_dispositions_for_stoppers(&mut system)
1439 .unwrap();
1440 assert_eq!(system.0[&SIGTSTP], Disposition::Ignore);
1441 assert_eq!(system.0[&SIGTTIN], Disposition::Ignore);
1442 assert_eq!(system.0[&SIGTTOU], Disposition::Ignore);
1443 }
1444
1445 #[test]
1446 fn disabling_internal_dispositions_for_initially_defaulted_signals() {
1447 let mut system = DummySystem::default();
1448 let mut trap_set = TrapSet::default();
1449 trap_set
1450 .enable_internal_disposition_for_sigchld(&mut system)
1451 .unwrap();
1452 trap_set
1453 .enable_internal_dispositions_for_terminators(&mut system)
1454 .unwrap();
1455 trap_set
1456 .enable_internal_dispositions_for_stoppers(&mut system)
1457 .unwrap();
1458 trap_set.disable_internal_dispositions(&mut system).unwrap();
1459 assert_eq!(system.0[&SIGCHLD], Disposition::Default);
1460 assert_eq!(system.0[&SIGINT], Disposition::Default);
1461 assert_eq!(system.0[&SIGTERM], Disposition::Default);
1462 assert_eq!(system.0[&SIGQUIT], Disposition::Default);
1463 assert_eq!(system.0[&SIGTSTP], Disposition::Default);
1464 assert_eq!(system.0[&SIGTTIN], Disposition::Default);
1465 assert_eq!(system.0[&SIGTTOU], Disposition::Default);
1466 }
1467
1468 fn ignore_signals(system: &mut DummySystem) {
1469 system.0.extend(
1470 [SIGCHLD, SIGINT, SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU]
1471 .into_iter()
1472 .map(|signal| (signal, Disposition::Ignore)),
1473 )
1474 }
1475
1476 #[test]
1477 fn disabling_internal_dispositions_for_initially_ignored_signals() {
1478 let mut system = DummySystem::default();
1479 ignore_signals(&mut system);
1480 let mut trap_set = TrapSet::default();
1481 trap_set
1482 .enable_internal_disposition_for_sigchld(&mut system)
1483 .unwrap();
1484 trap_set
1485 .enable_internal_dispositions_for_terminators(&mut system)
1486 .unwrap();
1487 trap_set
1488 .enable_internal_dispositions_for_stoppers(&mut system)
1489 .unwrap();
1490 trap_set.disable_internal_dispositions(&mut system).unwrap();
1491 assert_eq!(system.0[&SIGCHLD], Disposition::Ignore);
1492 assert_eq!(system.0[&SIGINT], Disposition::Ignore);
1493 assert_eq!(system.0[&SIGTERM], Disposition::Ignore);
1494 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1495 assert_eq!(system.0[&SIGTSTP], Disposition::Ignore);
1496 assert_eq!(system.0[&SIGTTIN], Disposition::Ignore);
1497 assert_eq!(system.0[&SIGTTOU], Disposition::Ignore);
1498 }
1499
1500 #[test]
1501 fn disabling_internal_dispositions_after_enabling_twice() {
1502 let mut system = DummySystem::default();
1503 ignore_signals(&mut system);
1504 let mut trap_set = TrapSet::default();
1505 trap_set
1506 .enable_internal_disposition_for_sigchld(&mut system)
1507 .unwrap();
1508 trap_set
1509 .enable_internal_disposition_for_sigchld(&mut system)
1510 .unwrap();
1511 trap_set
1512 .enable_internal_dispositions_for_terminators(&mut system)
1513 .unwrap();
1514 trap_set
1515 .enable_internal_dispositions_for_terminators(&mut system)
1516 .unwrap();
1517 trap_set
1518 .enable_internal_dispositions_for_stoppers(&mut system)
1519 .unwrap();
1520 trap_set
1521 .enable_internal_dispositions_for_stoppers(&mut system)
1522 .unwrap();
1523 trap_set.disable_internal_dispositions(&mut system).unwrap();
1524 assert_eq!(system.0[&SIGCHLD], Disposition::Ignore);
1525 assert_eq!(system.0[&SIGINT], Disposition::Ignore);
1526 assert_eq!(system.0[&SIGTERM], Disposition::Ignore);
1527 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1528 assert_eq!(system.0[&SIGTSTP], Disposition::Ignore);
1529 assert_eq!(system.0[&SIGTTIN], Disposition::Ignore);
1530 assert_eq!(system.0[&SIGTTOU], Disposition::Ignore);
1531 }
1532
1533 #[test]
1534 fn disabling_internal_dispositions_without_enabling() {
1535 let mut system = DummySystem::default();
1536 ignore_signals(&mut system);
1537 let mut trap_set = TrapSet::default();
1538 trap_set.disable_internal_dispositions(&mut system).unwrap();
1539 assert_eq!(system.0[&SIGCHLD], Disposition::Ignore);
1540 assert_eq!(system.0[&SIGINT], Disposition::Ignore);
1541 assert_eq!(system.0[&SIGTERM], Disposition::Ignore);
1542 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1543 assert_eq!(system.0[&SIGTSTP], Disposition::Ignore);
1544 assert_eq!(system.0[&SIGTTIN], Disposition::Ignore);
1545 assert_eq!(system.0[&SIGTTOU], Disposition::Ignore);
1546 }
1547
1548 #[test]
1549 fn reenabling_internal_dispositions() {
1550 let mut system = DummySystem::default();
1551 let mut trap_set = TrapSet::default();
1552 trap_set
1553 .enable_internal_disposition_for_sigchld(&mut system)
1554 .unwrap();
1555 trap_set
1556 .enable_internal_disposition_for_sigchld(&mut system)
1557 .unwrap();
1558 trap_set
1559 .enable_internal_dispositions_for_terminators(&mut system)
1560 .unwrap();
1561 trap_set
1562 .enable_internal_dispositions_for_terminators(&mut system)
1563 .unwrap();
1564 trap_set
1565 .enable_internal_dispositions_for_stoppers(&mut system)
1566 .unwrap();
1567 trap_set
1568 .enable_internal_dispositions_for_stoppers(&mut system)
1569 .unwrap();
1570 trap_set.disable_internal_dispositions(&mut system).unwrap();
1571 trap_set
1572 .enable_internal_disposition_for_sigchld(&mut system)
1573 .unwrap();
1574 trap_set
1575 .enable_internal_dispositions_for_terminators(&mut system)
1576 .unwrap();
1577 trap_set
1578 .enable_internal_dispositions_for_stoppers(&mut system)
1579 .unwrap();
1580 assert_eq!(system.0[&SIGCHLD], Disposition::Catch);
1581 assert_eq!(system.0[&SIGINT], Disposition::Catch);
1582 assert_eq!(system.0[&SIGTERM], Disposition::Ignore);
1583 assert_eq!(system.0[&SIGQUIT], Disposition::Ignore);
1584 assert_eq!(system.0[&SIGTSTP], Disposition::Ignore);
1585 assert_eq!(system.0[&SIGTTIN], Disposition::Ignore);
1586 assert_eq!(system.0[&SIGTTOU], Disposition::Ignore);
1587 }
1588
1589 #[test]
1590 fn setting_trap_to_ignore_after_enabling_internal_disposition() {
1591 let mut system = DummySystem::default();
1592 let mut trap_set = TrapSet::default();
1593 trap_set
1594 .enable_internal_disposition_for_sigchld(&mut system)
1595 .unwrap();
1596 let origin = Location::dummy("origin");
1597 let result = trap_set.set_action(&mut system, SIGCHLD, Action::Ignore, origin, false);
1598 assert_eq!(result, Ok(()));
1599 assert_eq!(system.0[&SIGCHLD], Disposition::Catch);
1600 }
1601
1602 #[test]
1603 fn resetting_trap_from_ignore_no_override_after_enabling_internal_dispositions() {
1604 let mut system = DummySystem::default();
1605 ignore_signals(&mut system);
1606 let mut trap_set = TrapSet::default();
1607 trap_set
1608 .enable_internal_disposition_for_sigchld(&mut system)
1609 .unwrap();
1610 trap_set
1611 .enable_internal_dispositions_for_terminators(&mut system)
1612 .unwrap();
1613 trap_set
1614 .enable_internal_dispositions_for_stoppers(&mut system)
1615 .unwrap();
1616
1617 for signal in [SIGCHLD, SIGINT] {
1618 let origin = Location::dummy("origin");
1619 let result = trap_set.set_action(&mut system, signal, Action::Default, origin, false);
1620 assert_eq!(result, Err(SetActionError::InitiallyIgnored));
1621 assert_eq!(system.0[&signal], Disposition::Catch);
1622 }
1623 for signal in [SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU] {
1624 let origin = Location::dummy("origin");
1625 let result = trap_set.set_action(&mut system, signal, Action::Default, origin, false);
1626 assert_eq!(result, Err(SetActionError::InitiallyIgnored));
1627 assert_eq!(system.0[&signal], Disposition::Ignore);
1628 }
1629 }
1630
1631 #[test]
1632 fn resetting_trap_from_ignore_override_after_enabling_internal_dispositions() {
1633 let mut system = DummySystem::default();
1634 ignore_signals(&mut system);
1635 let mut trap_set = TrapSet::default();
1636 trap_set
1637 .enable_internal_disposition_for_sigchld(&mut system)
1638 .unwrap();
1639 trap_set
1640 .enable_internal_dispositions_for_terminators(&mut system)
1641 .unwrap();
1642 trap_set
1643 .enable_internal_dispositions_for_stoppers(&mut system)
1644 .unwrap();
1645
1646 for signal in [SIGCHLD, SIGINT] {
1647 let origin = Location::dummy("origin");
1648 let result =
1649 trap_set.set_action(&mut system, signal, Action::Ignore, origin.clone(), true);
1650 assert_eq!(result, Ok(()));
1651 assert_eq!(
1652 trap_set.get_state(signal),
1653 (
1654 Some(&TrapState {
1655 action: Action::Ignore,
1656 origin: Origin::User(origin),
1657 pending: false
1658 }),
1659 None
1660 )
1661 );
1662 assert_eq!(system.0[&signal], Disposition::Catch);
1663 }
1664 for signal in [SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU] {
1665 let origin = Location::dummy("origin");
1666 let result =
1667 trap_set.set_action(&mut system, signal, Action::Ignore, origin.clone(), true);
1668 assert_eq!(result, Ok(()));
1669 assert_eq!(
1670 trap_set.get_state(signal),
1671 (
1672 Some(&TrapState {
1673 action: Action::Ignore,
1674 origin: Origin::User(origin),
1675 pending: false
1676 }),
1677 None
1678 )
1679 );
1680 assert_eq!(system.0[&signal], Disposition::Ignore);
1681 }
1682 }
1683
1684 #[test]
1685 fn disabling_internal_disposition_with_ignore_trap() {
1686 let signals = [SIGCHLD, SIGINT, SIGTERM, SIGQUIT, SIGTSTP, SIGTTIN, SIGTTOU];
1687
1688 let mut system = DummySystem::default();
1689 let mut trap_set = TrapSet::default();
1690 trap_set
1691 .enable_internal_disposition_for_sigchld(&mut system)
1692 .unwrap();
1693 trap_set
1694 .enable_internal_dispositions_for_terminators(&mut system)
1695 .unwrap();
1696 let origin = Location::dummy("origin");
1697 for signal in signals {
1698 trap_set
1699 .set_action(&mut system, signal, Action::Ignore, origin.clone(), false)
1700 .unwrap();
1701 }
1702 trap_set.disable_internal_dispositions(&mut system).unwrap();
1703
1704 for signal in signals {
1705 assert_eq!(
1706 trap_set.get_state(signal),
1707 (
1708 Some(&TrapState {
1709 action: Action::Ignore,
1710 origin: Origin::User(origin.clone()),
1711 pending: false
1712 }),
1713 None
1714 )
1715 );
1716 assert_eq!(system.0[&signal], Disposition::Ignore);
1717 }
1718 }
1719}