summaryrefslogtreecommitdiff
path: root/src/features.rs
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2014-10-06 18:11:03 -0700
committerCarl Lerche <me@carllerche.com>2014-10-06 18:11:03 -0700
commitc976be575f4fefcf03a70c5b87f898388150c8aa (patch)
tree9d00323114f31875de7c241476116e0fa239b4e5 /src/features.rs
parent3ecbe3364aa56f3352a07a85b146156bb246f515 (diff)
downloadnix-c976be575f4fefcf03a70c5b87f898388150c8aa.zip
Implement improved feature detection on Linux
Diffstat (limited to 'src/features.rs')
-rw-r--r--src/features.rs91
1 files changed, 88 insertions, 3 deletions
diff --git a/src/features.rs b/src/features.rs
index bfe3dc4a..269d88a0 100644
--- a/src/features.rs
+++ b/src/features.rs
@@ -2,14 +2,99 @@ pub use self::os::*;
#[cfg(target_os = "linux")]
mod os {
- pub fn atomic_cloexec() -> bool {
- true // TODO: Not on all kernel versions
+ use sys::utsname::uname;
+
+ // Features:
+ // * atomic cloexec on socket: 2.6.27
+ // * pipe2: 2.6.27
+ // * accept4: 2.6.28
+
+ static VERS_UNKNOWN: uint = 1;
+ static VERS_2_6_18: uint = 2;
+ static VERS_2_6_27: uint = 3;
+ static VERS_2_6_28: uint = 4;
+ static VERS_3: uint = 5;
+
+ fn parse_kernel_version() -> uint {
+ let u = uname();
+
+ #[inline]
+ fn digit(dst: &mut uint, b: u8) {
+ *dst *= 10;
+ *dst += (b - b'0') as uint;
+ }
+
+ let mut curr = 0u;
+ let mut major = 0;
+ let mut minor = 0;
+ let mut patch = 0;
+
+ for b in u.release().bytes() {
+ if curr >= 3 {
+ break;
+ }
+
+ match b {
+ b'.' | b'-' => {
+ curr += 1;
+ }
+ b'0'...b'9' => {
+ match curr {
+ 0 => digit(&mut major, b),
+ 1 => digit(&mut minor, b),
+ _ => digit(&mut patch, b),
+ }
+ }
+ _ => break,
+ }
+ }
+
+ if major >= 3 {
+ VERS_3
+ } else if major >= 2 {
+ if minor >= 7 {
+ VERS_UNKNOWN
+ } else if minor >= 6 {
+ if patch >= 28 {
+ VERS_2_6_28
+ } else if patch >= 27 {
+ VERS_2_6_27
+ } else {
+ VERS_2_6_18
+ }
+ } else {
+ VERS_UNKNOWN
+ }
+ } else {
+ VERS_UNKNOWN
+ }
+ }
+
+ fn kernel_version() -> uint {
+ static mut KERNEL_VERS: uint = 0;
+
+ unsafe {
+ if KERNEL_VERS == 0 {
+ KERNEL_VERS = parse_kernel_version();
+ }
+
+ KERNEL_VERS
+ }
+ }
+
+ pub fn socket_atomic_cloexec() -> bool {
+ kernel_version() >= VERS_2_6_27
+ }
+
+ #[test]
+ pub fn test_parsing_kernel_version() {
+ assert!(kernel_version() > 0);
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod os {
- pub fn atomic_cloexec() -> bool {
+ pub fn socket_atomic_cloexec() -> bool {
false
}
}