diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/features.rs | 91 | ||||
-rw-r--r-- | src/sys/socket.rs | 2 |
2 files changed, 89 insertions, 4 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 } } diff --git a/src/sys/socket.rs b/src/sys/socket.rs index edbbad97..8a99f708 100644 --- a/src/sys/socket.rs +++ b/src/sys/socket.rs @@ -162,7 +162,7 @@ mod consts { } pub fn socket(domain: AddressFamily, mut ty: SockType, flags: SockFlag) -> SysResult<Fd> { - let feat_atomic = features::atomic_cloexec(); + let feat_atomic = features::socket_atomic_cloexec(); if feat_atomic { ty = ty | flags.bits(); |