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