1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
use nix::unistd::*;
use nix::unistd::Fork::*;
use nix::sys::wait::*;
use std::ffi::CString;
#[test]
fn test_fork_and_waitpid() {
let pid = fork();
match pid {
Ok(Child) => {} // ignore child here
Ok(Parent(child_pid)) => {
// assert that child was created and pid > 0
assert!(child_pid > 0);
let wait_status = waitpid(child_pid, None);
match wait_status {
// assert that waitpid returned correct status and the pid is the one of the child
Ok(WaitStatus::Exited(pid_t)) => assert!(pid_t == child_pid),
// panic, must never happen
Ok(WaitStatus::StillAlive) => panic!("Child still alive, should never happen"),
// panic, waitpid should never fail
Err(_) => panic!("Error: waitpid Failed")
}
},
// panic, fork should never fail unless there is a serious problem with the OS
Err(_) => panic!("Error: Fork Failed")
}
}
#[test]
fn test_wait() {
let pid = fork();
match pid {
Ok(Child) => {} // ignore child here
Ok(Parent(child_pid)) => {
let wait_status = wait();
// just assert that (any) one child returns with WaitStatus::Exited
assert_eq!(wait_status, Ok(WaitStatus::Exited(child_pid)));
},
// panic, fork should never fail unless there is a serious problem with the OS
Err(_) => panic!("Error: Fork Failed")
}
}
#[test]
fn test_getpid() {
let pid = getpid();
let ppid = getppid();
assert!(pid > 0);
assert!(ppid > 0);
}
macro_rules! execve_test_factory(
($test_name:ident, $syscall:ident, $unix_sh:expr, $android_sh:expr) => (
#[test]
fn $test_name() {
// The `exec`d process will write to `writer`, and we'll read that
// data from `reader`.
let (reader, writer) = pipe().unwrap();
match fork().unwrap() {
Child => {
#[cfg(not(target_os = "android"))]
const SH_PATH: &'static [u8] = $unix_sh;
#[cfg(target_os = "android")]
const SH_PATH: &'static [u8] = $android_sh;
// Close stdout.
close(1).unwrap();
// Make `writer` be the stdout of the new process.
dup(writer).unwrap();
// exec!
$syscall(
&CString::new(SH_PATH).unwrap(),
&[CString::new(b"".as_ref()).unwrap(),
CString::new(b"-c".as_ref()).unwrap(),
CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
.as_ref()).unwrap()],
&[CString::new(b"foo=bar".as_ref()).unwrap(),
CString::new(b"baz=quux".as_ref()).unwrap()]).unwrap();
},
Parent(child_pid) => {
// Wait for the child to exit.
waitpid(child_pid, None).unwrap();
// Read 1024 bytes.
let mut buf = [0u8; 1024];
read(reader, &mut buf).unwrap();
// It should contain the things we printed using `/bin/sh`.
let string = String::from_utf8_lossy(&buf);
assert!(string.contains("nix!!!"));
assert!(string.contains("foo=bar"));
assert!(string.contains("baz=quux"));
}
}
}
)
);
execve_test_factory!(test_execve, execve, b"/bin/sh", b"/system/bin/sh");
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg(feature = "execvpe")]
execve_test_factory!(test_execvpe, execvpe, b"sh", b"sh");
|