1 use cfg_if::cfg_if;
2 
3 #[macro_export] macro_rules! skip {
4     ($($reason: expr),+) => {
5         use ::std::io::{self, Write};
6 
7         let stderr = io::stderr();
8         let mut handle = stderr.lock();
9         writeln!(handle, $($reason),+).unwrap();
10         return;
11     }
12 }
13 
14 cfg_if! {
15     if #[cfg(any(target_os = "android", target_os = "linux"))] {
16         #[macro_export] macro_rules! require_capability {
17             ($capname:ident) => {
18                 use ::caps::{Capability, CapSet, has_cap};
19 
20                 if !has_cap(None, CapSet::Effective, Capability::$capname)
21                     .unwrap()
22                 {
23                     skip!("Insufficient capabilities. Skipping test.");
24                 }
25             }
26         }
27     } else if #[cfg(not(target_os = "redox"))] {
28         #[macro_export] macro_rules! require_capability {
29             ($capname:ident) => {}
30         }
31     }
32 }
33 
34 /// Skip the test if we don't have the ability to mount file systems.
35 #[cfg(target_os = "freebsd")]
36 #[macro_export] macro_rules! require_mount {
37     ($name:expr) => {
38         use ::sysctl::CtlValue;
39         use nix::unistd::Uid;
40 
41         if !Uid::current().is_root() && CtlValue::Int(0) == ::sysctl::value("vfs.usermount").unwrap()
42         {
43             skip!("{} requires the ability to mount file systems. Skipping test.", $name);
44         }
45     }
46 }
47 
48 #[cfg(any(target_os = "linux", target_os= "android"))]
49 #[macro_export] macro_rules! skip_if_cirrus {
50     ($reason:expr) => {
51         if std::env::var_os("CIRRUS_CI").is_some() {
52             skip!("{}", $reason);
53         }
54     }
55 }
56 
57 #[cfg(target_os = "freebsd")]
58 #[macro_export] macro_rules! skip_if_jailed {
59     ($name:expr) => {
60         use ::sysctl::CtlValue;
61 
62         if let CtlValue::Int(1) = ::sysctl::value("security.jail.jailed")
63             .unwrap()
64         {
65             skip!("{} cannot run in a jail. Skipping test.", $name);
66         }
67     }
68 }
69 
70 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
71 #[macro_export] macro_rules! skip_if_not_root {
72     ($name:expr) => {
73         use nix::unistd::Uid;
74 
75         if !Uid::current().is_root() {
76             skip!("{} requires root privileges. Skipping test.", $name);
77         }
78     };
79 }
80 
81 cfg_if! {
82     if #[cfg(any(target_os = "android", target_os = "linux"))] {
83         #[macro_export] macro_rules! skip_if_seccomp {
84             ($name:expr) => {
85                 if let Ok(s) = std::fs::read_to_string("/proc/self/status") {
86                     for l in s.lines() {
87                         let mut fields = l.split_whitespace();
88                         if fields.next() == Some("Seccomp:") &&
89                             fields.next() != Some("0")
90                         {
91                             skip!("{} cannot be run in Seccomp mode.  Skipping test.",
92                                 stringify!($name));
93                         }
94                     }
95                 }
96             }
97         }
98     } else if #[cfg(not(target_os = "redox"))] {
99         #[macro_export] macro_rules! skip_if_seccomp {
100             ($name:expr) => {}
101         }
102     }
103 }
104 
105 cfg_if! {
106     if #[cfg(target_os = "linux")] {
107         #[macro_export] macro_rules! require_kernel_version {
108             ($name:expr, $version_requirement:expr) => {
109                 use semver::{Version, VersionReq};
110 
111                 let version_requirement = VersionReq::parse($version_requirement)
112                         .expect("Bad match_version provided");
113 
114                 let uname = nix::sys::utsname::uname();
115                 println!("{}", uname.sysname());
116                 println!("{}", uname.nodename());
117                 println!("{}", uname.release());
118                 println!("{}", uname.version());
119                 println!("{}", uname.machine());
120 
121                 // Fix stuff that the semver parser can't handle
122                 let fixed_release = &uname.release().to_string()
123                     // Fedora 33 reports version as 4.18.el8_2.x86_64 or
124                     // 5.18.200-fc33.x86_64.  Remove the underscore.
125                     .replace("_", "-")
126                     // Cirrus-CI reports version as 4.19.112+ .  Remove the +
127                     .replace("+", "");
128                 let mut version = Version::parse(fixed_release).unwrap();
129 
130                 //Keep only numeric parts
131                 version.pre = semver::Prerelease::EMPTY;
132                 version.build = semver::BuildMetadata::EMPTY;
133 
134                 if !version_requirement.matches(&version) {
135                     skip!("Skip {} because kernel version `{}` doesn't match the requirement `{}`",
136                         stringify!($name), version, version_requirement);
137                 }
138             }
139         }
140     }
141 }
142