1 extern crate bytes;
2 #[cfg(any(target_os = "android", target_os = "linux"))]
3 extern crate caps;
4 #[macro_use]
5 extern crate cfg_if;
6 #[macro_use]
7 extern crate nix;
8 #[macro_use]
9 extern crate lazy_static;
10 extern crate libc;
11 extern crate rand;
12 #[cfg(target_os = "freebsd")]
13 extern crate sysctl;
14 extern crate tempfile;
15
16 #[cfg(any(target_os = "android", target_os = "linux"))]
17 macro_rules! require_capability {
18 ($capname:ident) => {
19 use ::caps::{Capability, CapSet, has_cap};
20 use ::std::io::{self, Write};
21
22 if !has_cap(None, CapSet::Effective, Capability::$capname).unwrap() {
23 let stderr = io::stderr();
24 let mut handle = stderr.lock();
25 writeln!(handle, "Insufficient capabilities. Skipping test.")
26 .unwrap();
27 return;
28 }
29 }
30 }
31
32 #[cfg(target_os = "freebsd")]
33 macro_rules! skip_if_jailed {
34 ($name:expr) => {
35 use ::sysctl::CtlValue;
36
37 if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
38 .unwrap()
39 {
40 use ::std::io::Write;
41 let stderr = ::std::io::stderr();
42 let mut handle = stderr.lock();
43 writeln!(handle, "{} cannot run in a jail. Skipping test.", $name)
44 .unwrap();
45 return;
46 }
47 }
48 }
49
50 macro_rules! skip_if_not_root {
51 ($name:expr) => {
52 use nix::unistd::Uid;
53
54 if !Uid::current().is_root() {
55 use ::std::io::Write;
56 let stderr = ::std::io::stderr();
57 let mut handle = stderr.lock();
58 writeln!(handle, "{} requires root privileges. Skipping test.", $name).unwrap();
59 return;
60 }
61 };
62 }
63
64 mod sys;
65 mod test_dir;
66 mod test_fcntl;
67 #[cfg(any(target_os = "android",
68 target_os = "linux"))]
69 mod test_kmod;
70 #[cfg(any(target_os = "dragonfly",
71 target_os = "freebsd",
72 target_os = "fushsia",
73 target_os = "linux",
74 target_os = "netbsd"))]
75 mod test_mq;
76 mod test_net;
77 mod test_nix_path;
78 mod test_poll;
79 mod test_pty;
80 #[cfg(any(target_os = "android",
81 target_os = "freebsd",
82 target_os = "ios",
83 target_os = "linux",
84 target_os = "macos"))]
85 mod test_sendfile;
86 mod test_stat;
87 mod test_unistd;
88
89 use std::os::unix::io::RawFd;
90 use std::path::PathBuf;
91 use std::sync::{Mutex, RwLock, RwLockWriteGuard};
92 use nix::unistd::{chdir, getcwd, read};
93
94 /// Helper function analogous to `std::io::Read::read_exact`, but for `RawFD`s
read_exact(f: RawFd, buf: &mut [u8])95 fn read_exact(f: RawFd, buf: &mut [u8]) {
96 let mut len = 0;
97 while len < buf.len() {
98 // get_mut would be better than split_at_mut, but it requires nightly
99 let (_, remaining) = buf.split_at_mut(len);
100 len += read(f, remaining).unwrap();
101 }
102 }
103
104 lazy_static! {
105 /// Any test that changes the process's current working directory must grab
106 /// the RwLock exclusively. Any process that cares about the current
107 /// working directory must grab it shared.
108 pub static ref CWD_LOCK: RwLock<()> = RwLock::new(());
109 /// Any test that creates child processes must grab this mutex, regardless
110 /// of what it does with those children.
111 pub static ref FORK_MTX: Mutex<()> = Mutex::new(());
112 /// Any test that changes the process's supplementary groups must grab this
113 /// mutex
114 pub static ref GROUPS_MTX: Mutex<()> = Mutex::new(());
115 /// Any tests that loads or unloads kernel modules must grab this mutex
116 pub static ref KMOD_MTX: Mutex<()> = Mutex::new(());
117 /// Any test that calls ptsname(3) must grab this mutex.
118 pub static ref PTSNAME_MTX: Mutex<()> = Mutex::new(());
119 /// Any test that alters signal handling must grab this mutex.
120 pub static ref SIGNAL_MTX: Mutex<()> = Mutex::new(());
121 }
122
123 /// RAII object that restores a test's original directory on drop
124 struct DirRestore<'a> {
125 d: PathBuf,
126 _g: RwLockWriteGuard<'a, ()>
127 }
128
129 impl<'a> DirRestore<'a> {
new() -> Self130 fn new() -> Self {
131 let guard = ::CWD_LOCK.write()
132 .expect("Lock got poisoned by another test");
133 DirRestore{
134 _g: guard,
135 d: getcwd().unwrap(),
136 }
137 }
138 }
139
140 impl<'a> Drop for DirRestore<'a> {
drop(&mut self)141 fn drop(&mut self) {
142 let r = chdir(&self.d);
143 if std::thread::panicking() {
144 r.unwrap();
145 }
146 }
147 }
148