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 8 // Features: 9 // * atomic cloexec on socket: 2.6.27 10 // * pipe2: 2.6.27 11 // * accept4: 2.6.28 12 13 static VERS_UNKNOWN: usize = 1; 14 static VERS_2_6_18: usize = 2; 15 static VERS_2_6_27: usize = 3; 16 static VERS_2_6_28: usize = 4; 17 static VERS_3: usize = 5; 18 19 #[inline] digit(dst: &mut usize, b: u8)20 fn digit(dst: &mut usize, b: u8) { 21 *dst *= 10; 22 *dst += (b - b'0') as usize; 23 } 24 parse_kernel_version() -> usize25 fn parse_kernel_version() -> usize { 26 let u = uname(); 27 28 let mut curr: usize = 0; 29 let mut major: usize = 0; 30 let mut minor: usize = 0; 31 let mut patch: usize = 0; 32 33 for b in u.release().bytes() { 34 if curr >= 3 { 35 break; 36 } 37 38 match b { 39 b'.' | b'-' => { 40 curr += 1; 41 } 42 b'0'..=b'9' => { 43 match curr { 44 0 => digit(&mut major, b), 45 1 => digit(&mut minor, b), 46 _ => digit(&mut patch, b), 47 } 48 } 49 _ => break, 50 } 51 } 52 53 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() -> usize74 fn kernel_version() -> 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 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() >= VERS_2_6_27 89 } 90 91 #[test] test_parsing_kernel_version()92 pub fn test_parsing_kernel_version() { 93 assert!(kernel_version() > 0); 94 } 95 } 96 97 #[cfg(any( 98 target_os = "dragonfly", // Since ??? 99 target_os = "freebsd", // Since 10.0 100 target_os = "illumos", // Since ??? 101 target_os = "netbsd", // Since 6.0 102 target_os = "openbsd", // Since 5.7 103 target_os = "redox", // Since 1-july-2020 104 ))] 105 mod os { 106 /// Check if the OS supports atomic close-on-exec for sockets socket_atomic_cloexec() -> bool107 pub const fn socket_atomic_cloexec() -> bool { 108 true 109 } 110 } 111 112 #[cfg(any(target_os = "macos", 113 target_os = "ios", 114 target_os = "fuchsia", 115 target_os = "solaris"))] 116 mod os { 117 /// Check if the OS supports atomic close-on-exec for sockets socket_atomic_cloexec() -> bool118 pub const fn socket_atomic_cloexec() -> bool { 119 false 120 } 121 } 122