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
8    // Features:
9    // * atomic cloexec on socket: 2.6.27
10    // * pipe2: 2.6.27
11    // * accept4: 2.6.28
12
13    static VERS_UNKNOWN: usize = 1;
14    static VERS_2_6_18:  usize = 2;
15    static VERS_2_6_27:  usize = 3;
16    static VERS_2_6_28:  usize = 4;
17    static VERS_3:       usize = 5;
18
19    #[inline]
20    fn digit(dst: &mut usize, b: u8) {
21        *dst *= 10;
22        *dst += (b - b'0') as usize;
23    }
24
25    fn parse_kernel_version() -> usize {
26        let u = uname();
27
28        let mut curr:  usize = 0;
29        let mut major: usize = 0;
30        let mut minor: usize = 0;
31        let mut patch: usize = 0;
32
33        for b in u.release().bytes() {
34            if curr >= 3 {
35                break;
36            }
37
38            match b {
39                b'.' | b'-' => {
40                    curr += 1;
41                }
42                b'0'..=b'9' => {
43                    match curr {
44                        0 => digit(&mut major, b),
45                        1 => digit(&mut minor, b),
46                        _ => digit(&mut patch, b),
47                    }
48                }
49                _ => break,
50            }
51        }
52
53        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() -> 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            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() >= VERS_2_6_27
89    }
90
91    #[test]
92    pub fn test_parsing_kernel_version() {
93        assert!(kernel_version() > 0);
94    }
95}
96
97#[cfg(any(
98        target_os = "dragonfly",    // Since ???
99        target_os = "freebsd",      // Since 10.0
100        target_os = "illumos",      // Since ???
101        target_os = "netbsd",       // Since 6.0
102        target_os = "openbsd",      // Since 5.7
103        target_os = "redox",        // Since 1-july-2020
104))]
105mod os {
106    /// Check if the OS supports atomic close-on-exec for sockets
107    pub const fn socket_atomic_cloexec() -> bool {
108        true
109    }
110}
111
112#[cfg(any(target_os = "macos",
113          target_os = "ios",
114          target_os = "fuchsia",
115          target_os = "solaris"))]
116mod os {
117    /// Check if the OS supports atomic close-on-exec for sockets
118    pub const fn socket_atomic_cloexec() -> bool {
119        false
120    }
121}