• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use nix::errno::Errno;
2 use nix::unistd::*;
3 use nix::unistd::ForkResult::*;
4 use nix::sys::signal::*;
5 use nix::sys::wait::*;
6 use libc::_exit;
7 
8 #[test]
9 #[cfg(not(target_os = "redox"))]
test_wait_signal()10 fn test_wait_signal() {
11     let _m = crate::FORK_MTX.lock();
12 
13     // Safe: The child only calls `pause` and/or `_exit`, which are async-signal-safe.
14     match unsafe{fork()}.expect("Error: Fork Failed") {
15       Child => {
16           pause();
17           unsafe { _exit(123) }
18       },
19       Parent { child } => {
20           kill(child, Some(SIGKILL)).expect("Error: Kill Failed");
21           assert_eq!(waitpid(child, None), Ok(WaitStatus::Signaled(child, SIGKILL, false)));
22       },
23     }
24 }
25 
26 #[test]
test_wait_exit()27 fn test_wait_exit() {
28     let _m = crate::FORK_MTX.lock();
29 
30     // Safe: Child only calls `_exit`, which is async-signal-safe.
31     match unsafe{fork()}.expect("Error: Fork Failed") {
32       Child => unsafe { _exit(12); },
33       Parent { child } => {
34           assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 12)));
35       },
36     }
37 }
38 
39 #[test]
test_waitstatus_from_raw()40 fn test_waitstatus_from_raw() {
41     let pid = Pid::from_raw(1);
42     assert_eq!(WaitStatus::from_raw(pid, 0x0002), Ok(WaitStatus::Signaled(pid, Signal::SIGINT, false)));
43     assert_eq!(WaitStatus::from_raw(pid, 0x0200), Ok(WaitStatus::Exited(pid, 2)));
44     assert_eq!(WaitStatus::from_raw(pid, 0x7f7f), Err(Errno::EINVAL));
45 }
46 
47 #[test]
test_waitstatus_pid()48 fn test_waitstatus_pid() {
49     let _m = crate::FORK_MTX.lock();
50 
51     match unsafe{fork()}.unwrap() {
52         Child => unsafe { _exit(0) },
53         Parent { child } => {
54             let status = waitpid(child, None).unwrap();
55             assert_eq!(status.pid(), Some(child));
56         }
57     }
58 }
59 
60 #[cfg(any(target_os = "linux", target_os = "android"))]
61 // FIXME: qemu-user doesn't implement ptrace on most arches
62 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
63 mod ptrace {
64     use nix::sys::ptrace::{self, Options, Event};
65     use nix::sys::signal::*;
66     use nix::sys::wait::*;
67     use nix::unistd::*;
68     use nix::unistd::ForkResult::*;
69     use libc::_exit;
70     use crate::*;
71 
ptrace_child() -> !72     fn ptrace_child() -> ! {
73         ptrace::traceme().unwrap();
74         // As recommended by ptrace(2), raise SIGTRAP to pause the child
75         // until the parent is ready to continue
76         raise(SIGTRAP).unwrap();
77         unsafe { _exit(0) }
78     }
79 
ptrace_parent(child: Pid)80     fn ptrace_parent(child: Pid) {
81         // Wait for the raised SIGTRAP
82         assert_eq!(waitpid(child, None), Ok(WaitStatus::Stopped(child, SIGTRAP)));
83         // We want to test a syscall stop and a PTRACE_EVENT stop
84         assert!(ptrace::setoptions(child, Options::PTRACE_O_TRACESYSGOOD | Options::PTRACE_O_TRACEEXIT).is_ok());
85 
86         // First, stop on the next system call, which will be exit()
87         assert!(ptrace::syscall(child, None).is_ok());
88         assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceSyscall(child)));
89         // Then get the ptrace event for the process exiting
90         assert!(ptrace::cont(child, None).is_ok());
91         assert_eq!(waitpid(child, None), Ok(WaitStatus::PtraceEvent(child, SIGTRAP, Event::PTRACE_EVENT_EXIT as i32)));
92         // Finally get the normal wait() result, now that the process has exited
93         assert!(ptrace::cont(child, None).is_ok());
94         assert_eq!(waitpid(child, None), Ok(WaitStatus::Exited(child, 0)));
95     }
96 
97     #[test]
test_wait_ptrace()98     fn test_wait_ptrace() {
99         require_capability!("test_wait_ptrace", CAP_SYS_PTRACE);
100         let _m = crate::FORK_MTX.lock();
101 
102         match unsafe{fork()}.expect("Error: Fork Failed") {
103             Child => ptrace_child(),
104             Parent { child } => ptrace_parent(child),
105         }
106     }
107 }
108