Simplify kernel version parsing

reviewable/pr641/r1
Tamir Duberstein 2 years ago
parent c89c485bca
commit 16ed110359
No known key found for this signature in database

@ -13,6 +13,5 @@ libc = { version = "0.2.105" }
log = "0.4"
object = { version = "0.31", default-features = false, features = ["std", "read_core", "elf"] }
rbpf = "0.2.0"
regex = "1"
tempfile = "3.3.0"
tokio = { version = "1.24", features = ["rt", "rt-multi-thread", "sync", "time"] }

@ -1,23 +1,42 @@
use anyhow::bail;
use anyhow::{anyhow, Context as _};
use libc::{uname, utsname};
use regex::Regex;
use std::{cell::OnceCell, ffi::CStr, mem};
use std::{ffi::CStr, io::Error, mem};
pub fn kernel_version() -> anyhow::Result<(u8, u8, u8)> {
static mut RE: OnceCell<Regex> = OnceCell::new();
let re =
unsafe { &mut RE }.get_or_init(|| Regex::new(r"^([0-9]+)\.([0-9]+)\.([0-9]+)").unwrap());
let mut data: utsname = unsafe { mem::zeroed() };
let ret = unsafe { uname(&mut data) };
assert!(ret >= 0, "libc::uname failed.");
let release_cstr = unsafe { CStr::from_ptr(data.release.as_ptr()) };
let release = release_cstr.to_string_lossy();
if let Some(caps) = re.captures(&release) {
let major = caps.get(1).unwrap().as_str().parse().unwrap();
let minor = caps.get(2).unwrap().as_str().parse().unwrap();
let patch = caps.get(3).unwrap().as_str().parse().unwrap();
Ok((major, minor, patch))
} else {
bail!("no kernel version found");
if ret != 0 {
return Err(Error::last_os_error()).context("uname failed");
}
let utsname { release, .. } = data;
let release: &[u8] =
unsafe { std::slice::from_raw_parts(release.as_ptr() as _, release.len()) };
let s = CStr::from_bytes_until_nul(release)?;
let s = s.to_str()?;
// Adapted from https://github.com/eminence/procfs/blob/d7ea846/procfs/src/sys/kernel/mod.rs#L51-L70.
let pos = s.find(|c: char| c != '.' && !c.is_ascii_digit());
let kernel = if let Some(pos) = pos {
let (s, _) = s.split_at(pos);
s
} else {
s
};
let mut kernel_split = kernel.split('.');
let major = kernel_split
.next()
.ok_or(anyhow!("Missing major version component"))?;
let minor = kernel_split
.next()
.ok_or(anyhow!("Missing minor version component"))?;
let patch = kernel_split
.next()
.ok_or(anyhow!("Missing patch version component"))?;
let major = major.parse().context("Failed to parse major version")?;
let minor = minor.parse().context("Failed to parse minor version")?;
let patch = patch.parse().context("Failed to parse patch version")?;
Ok((major, minor, patch))
}

Loading…
Cancel
Save