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 std::os::unix::ffi::OsStrExt;
7    use crate::sys::utsname::uname;
8    use crate::Result;
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' => {
45                    match curr {
46                        0 => digit(&mut major, b),
47                        1 => digit(&mut minor, b),
48                        _ => digit(&mut patch, b),
49                    }
50                }
51                _ => break,
52            }
53        }
54
55        Ok(if major >= 3 {
56            VERS_3
57        } else if major >= 2 {
58            if minor >= 7 {
59                VERS_UNKNOWN
60            } else if minor >= 6 {
61                if patch >= 28 {
62                    VERS_2_6_28
63                } else if patch >= 27 {
64                    VERS_2_6_27
65                } else {
66                    VERS_2_6_18
67                }
68            } else {
69                VERS_UNKNOWN
70            }
71        } else {
72            VERS_UNKNOWN
73        })
74    }
75
76    fn kernel_version() -> Result<usize> {
77        static mut KERNEL_VERS: usize = 0;
78
79        unsafe {
80            if KERNEL_VERS == 0 {
81                KERNEL_VERS = parse_kernel_version()?;
82            }
83
84            Ok(KERNEL_VERS)
85        }
86    }
87
88    /// Check if the OS supports atomic close-on-exec for sockets
89    pub fn socket_atomic_cloexec() -> bool {
90        kernel_version().map(|version| version >= VERS_2_6_27).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(target_os = "macos",
115          target_os = "ios",
116          target_os = "fuchsia",
117          target_os = "solaris"))]
118mod os {
119    /// Check if the OS supports atomic close-on-exec for sockets
120    pub const fn socket_atomic_cloexec() -> bool {
121        false
122    }
123}