nix/
features.rs

1//! Feature tests for OS functionality
2pub use self::os::*;
3
4#[cfg(any(target_os = "linux", target_os = "android"))]
5mod os {
6    use crate::sys::utsname::uname;
7    use crate::Result;
8    use std::os::unix::ffi::OsStrExt;
9
10    // Features:
11    // * atomic cloexec on socket: 2.6.27
12    // * pipe2: 2.6.27
13    // * accept4: 2.6.28
14
15    static VERS_UNKNOWN: usize = 1;
16    static VERS_2_6_18: usize = 2;
17    static VERS_2_6_27: usize = 3;
18    static VERS_2_6_28: usize = 4;
19    static VERS_3: usize = 5;
20
21    #[inline]
22    fn digit(dst: &mut usize, b: u8) {
23        *dst *= 10;
24        *dst += (b - b'0') as usize;
25    }
26
27    fn parse_kernel_version() -> Result<usize> {
28        let u = uname()?;
29
30        let mut curr: usize = 0;
31        let mut major: usize = 0;
32        let mut minor: usize = 0;
33        let mut patch: usize = 0;
34
35        for &b in u.release().as_bytes() {
36            if curr >= 3 {
37                break;
38            }
39
40            match b {
41                b'.' | b'-' => {
42                    curr += 1;
43                }
44                b'0'..=b'9' => match curr {
45                    0 => digit(&mut major, b),
46                    1 => digit(&mut minor, b),
47                    _ => digit(&mut patch, b),
48                },
49                _ => break,
50            }
51        }
52
53        Ok(if major >= 3 {
54            VERS_3
55        } else if major >= 2 {
56            if minor >= 7 {
57                VERS_UNKNOWN
58            } else if minor >= 6 {
59                if patch >= 28 {
60                    VERS_2_6_28
61                } else if patch >= 27 {
62                    VERS_2_6_27
63                } else {
64                    VERS_2_6_18
65                }
66            } else {
67                VERS_UNKNOWN
68            }
69        } else {
70            VERS_UNKNOWN
71        })
72    }
73
74    fn kernel_version() -> Result<usize> {
75        static mut KERNEL_VERS: usize = 0;
76
77        unsafe {
78            if KERNEL_VERS == 0 {
79                KERNEL_VERS = parse_kernel_version()?;
80            }
81
82            Ok(KERNEL_VERS)
83        }
84    }
85
86    /// Check if the OS supports atomic close-on-exec for sockets
87    pub fn socket_atomic_cloexec() -> bool {
88        kernel_version()
89            .map(|version| version >= VERS_2_6_27)
90            .unwrap_or(false)
91    }
92
93    #[test]
94    pub fn test_parsing_kernel_version() {
95        assert!(kernel_version().unwrap() > 0);
96    }
97}
98
99#[cfg(any(
100        target_os = "dragonfly",    // Since ???
101        target_os = "freebsd",      // Since 10.0
102        target_os = "illumos",      // Since ???
103        target_os = "netbsd",       // Since 6.0
104        target_os = "openbsd",      // Since 5.7
105        target_os = "redox",        // Since 1-july-2020
106))]
107mod os {
108    /// Check if the OS supports atomic close-on-exec for sockets
109    pub const fn socket_atomic_cloexec() -> bool {
110        true
111    }
112}
113
114#[cfg(any(
115    target_os = "macos",
116    target_os = "ios",
117    target_os = "fuchsia",
118    target_os = "haiku",
119    target_os = "solaris"
120))]
121mod os {
122    /// Check if the OS supports atomic close-on-exec for sockets
123    pub const fn socket_atomic_cloexec() -> bool {
124        false
125    }
126}