//! 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 { 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 { 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 } }