nix/
features.rs

1//! Feature tests for OS functionality
2pub use self::os::*;
3
4#[cfg(linux_android)]
5mod os {
6    use crate::sys::utsname::uname;
7    use crate::Result;
8    use std::os::unix::ffi::OsStrExt;
9    use std::sync::atomic::{AtomicUsize, Ordering};
10
11    // Features:
12    // * atomic cloexec on socket: 2.6.27
13    // * pipe2: 2.6.27
14    // * accept4: 2.6.28
15
16    static VERS_UNKNOWN: usize = 1;
17    static VERS_2_6_18: usize = 2;
18    static VERS_2_6_27: usize = 3;
19    static VERS_2_6_28: usize = 4;
20    static VERS_3: usize = 5;
21
22    #[inline]
23    fn digit(dst: &mut usize, b: u8) {
24        *dst *= 10;
25        *dst += (b - b'0') as usize;
26    }
27
28    fn parse_kernel_version() -> Result<usize> {
29        let u = uname()?;
30
31        let mut curr: usize = 0;
32        let mut major: usize = 0;
33        let mut minor: usize = 0;
34        let mut patch: usize = 0;
35
36        for &b in u.release().as_bytes() {
37            if curr >= 3 {
38                break;
39            }
40
41            match b {
42                b'.' | b'-' => {
43                    curr += 1;
44                }
45                b'0'..=b'9' => match curr {
46                    0 => digit(&mut major, b),
47                    1 => digit(&mut minor, b),
48                    _ => digit(&mut patch, b),
49                },
50                _ => break,
51            }
52        }
53
54        Ok(if major >= 3 {
55            VERS_3
56        } else if major >= 2 {
57            if minor >= 7 {
58                VERS_UNKNOWN
59            } else if minor >= 6 {
60                if patch >= 28 {
61                    VERS_2_6_28
62                } else if patch >= 27 {
63                    VERS_2_6_27
64                } else {
65                    VERS_2_6_18
66                }
67            } else {
68                VERS_UNKNOWN
69            }
70        } else {
71            VERS_UNKNOWN
72        })
73    }
74
75    fn kernel_version() -> Result<usize> {
76        static KERNEL_VERS: AtomicUsize = AtomicUsize::new(0);
77        let mut kernel_vers = KERNEL_VERS.load(Ordering::Relaxed);
78
79        if kernel_vers == 0 {
80            kernel_vers = parse_kernel_version()?;
81            KERNEL_VERS.store(kernel_vers, Ordering::Relaxed);
82        }
83
84        Ok(kernel_vers)
85    }
86
87    /// Check if the OS supports atomic close-on-exec for sockets
88    pub fn socket_atomic_cloexec() -> bool {
89        kernel_version()
90            .map(|version| version >= VERS_2_6_27)
91            .unwrap_or(false)
92    }
93
94    #[test]
95    pub fn test_parsing_kernel_version() {
96        assert!(kernel_version().unwrap() > 0);
97    }
98}
99
100#[cfg(any(
101        freebsdlike,                // FreeBSD since 10.0 DragonFlyBSD since ???
102        netbsdlike,                 // NetBSD since 6.0 OpenBSD since 5.7
103        target_os = "hurd",         // Since glibc 2.28
104        target_os = "illumos",      // Since ???
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 = "aix",
116    apple_targets,
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}