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