• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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