| //! Feature tests for OS functionality |
| pub use self::os::*; |
| |
| #[cfg(linux_android)] |
| mod os { |
| use crate::sys::utsname::uname; |
| use crate::Result; |
| use std::os::unix::ffi::OsStrExt; |
| use std::sync::atomic::{AtomicUsize, Ordering}; |
| |
| // Features: |
| // * atomic cloexec on socket: 2.6.27 |
| // * pipe2: 2.6.27 |
| // * accept4: 2.6.28 |
| |
| static VERS_UNKNOWN: usize = 1; |
| static VERS_2_6_18: usize = 2; |
| static VERS_2_6_27: usize = 3; |
| static VERS_2_6_28: usize = 4; |
| static VERS_3: usize = 5; |
| |
| #[inline] |
| fn digit(dst: &mut usize, b: u8) { |
| *dst *= 10; |
| *dst += (b - b'0') as usize; |
| } |
| |
| fn parse_kernel_version() -> Result<usize> { |
| let u = uname()?; |
| |
| let mut curr: usize = 0; |
| let mut major: usize = 0; |
| let mut minor: usize = 0; |
| let mut patch: usize = 0; |
| |
| for &b in u.release().as_bytes() { |
| if curr >= 3 { |
| break; |
| } |
| |
| match b { |
| b'.' | b'-' => { |
| curr += 1; |
| } |
| b'0'..=b'9' => match curr { |
| 0 => digit(&mut major, b), |
| 1 => digit(&mut minor, b), |
| _ => digit(&mut patch, b), |
| }, |
| _ => break, |
| } |
| } |
| |
| Ok(if major >= 3 { |
| VERS_3 |
| } else if major >= 2 { |
| if minor >= 7 { |
| VERS_UNKNOWN |
| } else if minor >= 6 { |
| if patch >= 28 { |
| VERS_2_6_28 |
| } else if patch >= 27 { |
| VERS_2_6_27 |
| } else { |
| VERS_2_6_18 |
| } |
| } else { |
| VERS_UNKNOWN |
| } |
| } else { |
| VERS_UNKNOWN |
| }) |
| } |
| |
| fn kernel_version() -> Result<usize> { |
| static KERNEL_VERS: AtomicUsize = AtomicUsize::new(0); |
| let mut kernel_vers = KERNEL_VERS.load(Ordering::Relaxed); |
| |
| if kernel_vers == 0 { |
| kernel_vers = parse_kernel_version()?; |
| KERNEL_VERS.store(kernel_vers, Ordering::Relaxed); |
| } |
| |
| Ok(kernel_vers) |
| } |
| |
| /// Check if the OS supports atomic close-on-exec for sockets |
| pub fn socket_atomic_cloexec() -> bool { |
| kernel_version() |
| .map(|version| version >= VERS_2_6_27) |
| .unwrap_or(false) |
| } |
| |
| #[test] |
| pub fn test_parsing_kernel_version() { |
| assert!(kernel_version().unwrap() > 0); |
| } |
| } |
| |
| #[cfg(any( |
| freebsdlike, // FreeBSD since 10.0 DragonFlyBSD since ??? |
| netbsdlike, // NetBSD since 6.0 OpenBSD since 5.7 |
| target_os = "hurd", // Since glibc 2.28 |
| target_os = "illumos", // Since ??? |
| target_os = "redox", // Since 1-july-2020 |
| ))] |
| mod os { |
| /// Check if the OS supports atomic close-on-exec for sockets |
| pub const fn socket_atomic_cloexec() -> bool { |
| true |
| } |
| } |
| |
| #[cfg(any( |
| target_os = "aix", |
| apple_targets, |
| target_os = "fuchsia", |
| target_os = "haiku", |
| target_os = "solaris" |
| ))] |
| mod os { |
| /// Check if the OS supports atomic close-on-exec for sockets |
| pub const fn socket_atomic_cloexec() -> bool { |
| false |
| } |
| } |