1 #[macro_use]
2 extern crate cfg_if;
3 #[cfg_attr(not(target_os = "redox"), macro_use)]
4 extern crate nix;
5 #[macro_use]
6 extern crate lazy_static;
7
8 macro_rules! skip {
9 ($($reason: expr),+) => {
10 use ::std::io::{self, Write};
11
12 let stderr = io::stderr();
13 let mut handle = stderr.lock();
14 writeln!(handle, $($reason),+).unwrap();
15 return;
16 }
17 }
18
19 cfg_if! {
20 if #[cfg(any(target_os = "android", target_os = "linux"))] {
21 macro_rules! require_capability {
22 ($capname:ident) => {
23 use ::caps::{Capability, CapSet, has_cap};
24
25 if !has_cap(None, CapSet::Effective, Capability::$capname)
26 .unwrap()
27 {
28 skip!("Insufficient capabilities. Skipping test.");
29 }
30 }
31 }
32 } else if #[cfg(not(target_os = "redox"))] {
33 macro_rules! require_capability {
34 ($capname:ident) => {}
35 }
36 }
37 }
38
39 #[cfg(target_os = "freebsd")]
40 macro_rules! skip_if_jailed {
41 ($name:expr) => {
42 use ::sysctl::CtlValue;
43
44 if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
45 .unwrap()
46 {
47 skip!("{} cannot run in a jail. Skipping test.", $name);
48 }
49 }
50 }
51
52 #[cfg(not(target_os = "redox"))]
53 macro_rules! skip_if_not_root {
54 ($name:expr) => {
55 use nix::unistd::Uid;
56
57 if !Uid::current().is_root() {
58 skip!("{} requires root privileges. Skipping test.", $name);
59 }
60 };
61 }
62
63 cfg_if! {
64 if #[cfg(any(target_os = "android", target_os = "linux"))] {
65 macro_rules! skip_if_seccomp {
66 ($name:expr) => {
67 if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
68 for l in s.lines() {
69 let mut fields = l.split_whitespace();
70 if fields.next() == Some("Seccomp:") &&
71 fields.next() != Some("0")
72 {
73 skip!("{} cannot be run in Seccomp mode. Skipping test.",
74 stringify!($name));
75 }
76 }
77 }
78 }
79 }
80 } else if #[cfg(not(target_os = "redox"))] {
81 macro_rules! skip_if_seccomp {
82 ($name:expr) => {}
83 }
84 }
85 }
86
87 cfg_if! {
88 if #[cfg(target_os = "linux")] {
89 macro_rules! require_kernel_version {
90 ($name:expr, $version_requirement:expr) => {
91 use semver::{Version, VersionReq};
92
93 let version_requirement = VersionReq::parse($version_requirement)
94 .expect("Bad match_version provided");
95
96 let uname = nix::sys::utsname::uname();
97
98 let mut version = Version::parse(uname.release()).unwrap();
99
100 //Keep only numeric parts
101 version.pre.clear();
102 version.build.clear();
103
104 if !version_requirement.matches(&version) {
105 skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
106 stringify!($name), version, version_requirement);
107 }
108 }
109 }
110 }
111 }
112
113 mod sys;
114 #[cfg(not(target_os = "redox"))]
115 mod test_dir;
116 mod test_fcntl;
117 #[cfg(any(target_os = "android",
118 target_os = "linux"))]
119 mod test_kmod;
120 #[cfg(any(target_os = "dragonfly",
121 target_os = "freebsd",
122 target_os = "fushsia",
123 target_os = "linux",
124 target_os = "netbsd"))]
125 mod test_mq;
126 #[cfg(not(target_os = "redox"))]
127 mod test_net;
128 mod test_nix_path;
129 mod test_poll;
130 #[cfg(not(target_os = "redox"))]
131 mod test_pty;
132 #[cfg(any(target_os = "android",
133 target_os = "linux"))]
134 mod test_sched;
135 #[cfg(any(target_os = "android",
136 target_os = "freebsd",
137 target_os = "ios",
138 target_os = "linux",
139 target_os = "macos"))]
140 mod test_sendfile;
141 mod test_stat;
142 mod test_unistd;
143
144 use std::os::unix::io::RawFd;
145 use std::path::PathBuf;
146 use std::sync::{Mutex, RwLock, RwLockWriteGuard};
147 use nix::unistd::{chdir, getcwd, read};
148
149 /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
read_exact(f: RawFd, buf: &mut [u8])150 fn read_exact(f: RawFd, buf: &mut [u8]) {
151 let mut len = 0;
152 while len < buf.len() {
153 // get_mut would be better than split_at_mut, but it requires nightly
154 let (_, remaining) = buf.split_at_mut(len);
155 len += read(f, remaining).unwrap();
156 }
157 }
158
159 lazy_static! {
160 /// Any test that changes the process's current working directory must grab
161 /// the RwLock exclusively. Any process that cares about the current
162 /// working directory must grab it shared.
163 pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
164 /// Any test that creates child processes must grab this mutex, regardless
165 /// of what it does with those children.
166 pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
167 /// Any test that changes the process's supplementary groups must grab this
168 /// mutex
169 pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
170 /// Any tests that loads or unloads kernel modules must grab this mutex
171 pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
172 /// Any test that calls ptsname(3) must grab this mutex.
173 pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
174 /// Any test that alters signal handling must grab this mutex.
175 pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
176 }
177
178 /// RAII object that restores a test's original directory on drop
179 struct DirRestore<'a> {
180 d: PathBuf,
181 _g: RwLockWriteGuard<'a, ()>
182 }
183
184 impl<'a> DirRestore<'a> {
new() -> Self185 fn new() -> Self {
186 let guard = crate::CWD_LOCK.write()
187 .expect("Lock got poisoned by another test");
188 DirRestore{
189 _g: guard,
190 d: getcwd().unwrap(),
191 }
192 }
193 }
194
195 impl<'a> Drop for DirRestore<'a> {
drop(&mut self)196 fn drop(&mut self) {
197 let r = chdir(&self.d);
198 if std::thread::panicking() {
199 r.unwrap();
200 }
201 }
202 }
203