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