1 //! Feature tests for OS functionality 2 pub use self::os::*; 3 4 #[cfg(linux_android)] 5 mod 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] digit(dst: &mut usize, b: u8)23 fn digit(dst: &mut usize, b: u8) { 24 *dst *= 10; 25 *dst += (b - b'0') as usize; 26 } 27 parse_kernel_version() -> Result<usize>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 kernel_version() -> Result<usize>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 socket_atomic_cloexec() -> bool88 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] test_parsing_kernel_version()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 ))] 107 mod os { 108 /// Check if the OS supports atomic close-on-exec for sockets socket_atomic_cloexec() -> bool109 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 ))] 121 mod os { 122 /// Check if the OS supports atomic close-on-exec for sockets socket_atomic_cloexec() -> bool123 pub const fn socket_atomic_cloexec() -> bool { 124 false 125 } 126 } 127