1 //! Feature tests for OS functionality 2 pub use self::os::*; 3 4 #[cfg(any(target_os = "linux", target_os = "android"))] 5 mod os { 6 use crate::sys::utsname::uname; 7 use crate::Result; 8 use std::os::unix::ffi::OsStrExt; 9 10 // Features: 11 // * atomic cloexec on socket: 2.6.27 12 // * pipe2: 2.6.27 13 // * accept4: 2.6.28 14 15 static VERS_UNKNOWN: usize = 1; 16 static VERS_2_6_18: usize = 2; 17 static VERS_2_6_27: usize = 3; 18 static VERS_2_6_28: usize = 4; 19 static VERS_3: usize = 5; 20 21 #[inline] digit(dst: &mut usize, b: u8)22 fn digit(dst: &mut usize, b: u8) { 23 *dst *= 10; 24 *dst += (b - b'0') as usize; 25 } 26 parse_kernel_version() -> Result<usize>27 fn parse_kernel_version() -> Result<usize> { 28 let u = uname()?; 29 30 let mut curr: usize = 0; 31 let mut major: usize = 0; 32 let mut minor: usize = 0; 33 let mut patch: usize = 0; 34 35 for &b in u.release().as_bytes() { 36 if curr >= 3 { 37 break; 38 } 39 40 match b { 41 b'.' | b'-' => { 42 curr += 1; 43 } 44 b'0'..=b'9' => match curr { 45 0 => digit(&mut major, b), 46 1 => digit(&mut minor, b), 47 _ => digit(&mut patch, b), 48 }, 49 _ => break, 50 } 51 } 52 53 Ok(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 kernel_version() -> Result<usize>74 fn kernel_version() -> Result<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 Ok(KERNEL_VERS) 83 } 84 } 85 86 /// Check if the OS supports atomic close-on-exec for sockets socket_atomic_cloexec() -> bool87 pub fn socket_atomic_cloexec() -> bool { 88 kernel_version() 89 .map(|version| version >= VERS_2_6_27) 90 .unwrap_or(false) 91 } 92 93 #[test] test_parsing_kernel_version()94 pub fn test_parsing_kernel_version() { 95 assert!(kernel_version().unwrap() > 0); 96 } 97 } 98 99 #[cfg(any( 100 target_os = "dragonfly", // Since ??? 101 target_os = "freebsd", // Since 10.0 102 target_os = "illumos", // Since ??? 103 target_os = "netbsd", // Since 6.0 104 target_os = "openbsd", // Since 5.7 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 = "macos", 116 target_os = "ios", 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