1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
use std::os::raw::c_char; use std::ffi::CStr; use std::mem; use std::str::from_utf8_unchecked; use std::str::FromStr; use std::fs; pub fn uname() -> Result<::libc::utsname, ()> { let mut uname = unsafe { mem::zeroed() }; let res = unsafe { ::libc::uname(&mut uname) }; if res < 0 { Err(()) } else { Ok(uname) } } #[inline] pub fn get_kernel_internal_version() -> Option<u32> { let version = if let Ok(version) = fs::read_to_string("/proc/version_signature") { parse_version_signature(&version.trim())? } else { to_str(&uname().ok()?.release).into() }; parse_version(&version).map(|(major, minor, patch)| { major << 16 | minor << 8 | patch }) } #[inline] pub fn get_fqdn() -> Result<String, ()> { let uname = uname()?; let mut hostname = to_str(&uname.nodename).to_string(); let domainname = to_str(&uname.domainname); if domainname != "(none)" { hostname.push_str("."); hostname.push_str(domainname); } Ok(hostname) } #[inline] pub fn to_str(bytes: &[c_char]) -> &str { unsafe { from_utf8_unchecked(CStr::from_ptr(bytes.as_ptr()).to_bytes()) } } fn parse_version_signature(signature: &str) -> Option<String> { let parts: Vec<_> = signature.split(" ").collect(); if parts.len() != 3 { return None; } parts.last().map(|v| v.clone().into()) } fn parse_version(version: &str) -> Option<(u32, u32, u32)> { if let Some(version) = version.splitn(2, "-").next() { let parts: Vec<_> = version.splitn(3, ".").filter_map(|v| u32::from_str(v).ok()).collect(); if parts.len() != 3 { return None; } return Some((parts[0], parts[1], parts[2])) } None } #[cfg(test)] mod test { use super::*; #[test] fn test_parse_version() { assert_eq!(parse_version("4.15.18"), Some((4, 15, 18))); assert_eq!(parse_version("4.15.1-generic"), Some((4, 15, 1))); assert_eq!(parse_version("4.15.1-generic-foo"), Some((4, 15, 1))); assert_eq!(parse_version("4.3.2.1"), None); assert_eq!(parse_version("4.2.foo"), None); assert_eq!(parse_version("4.2."), None); assert_eq!(parse_version("4.2"), None); assert_eq!(parse_version("foo"), None); assert_eq!(parse_version(""), None); } #[test] fn test_parse_version_signature() { assert_eq!(parse_version_signature("Ubuntu 4.15.0-55.60-generic 4.15.18"), Some("4.15.18".into())); assert_eq!(parse_version_signature("Ubuntu 4.15.0-55.60-generic 4.15.18 foo"), None); assert_eq!(parse_version_signature("Ubuntu 4.15.0-55.60-generic"), None); } }