From b5ebcb7cc5fd0f719567b97f682a0ea0f8e0dc13 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 10 Jul 2023 21:07:42 -0400 Subject: [PATCH 1/5] Remove verifier log special case --- aya-obj/src/btf/btf.rs | 2 +- aya/src/programs/mod.rs | 3 +-- aya/src/sys/bpf.rs | 16 ++++------------ 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/aya-obj/src/btf/btf.rs b/aya-obj/src/btf/btf.rs index 295fb55e..a9049b1e 100644 --- a/aya-obj/src/btf/btf.rs +++ b/aya-obj/src/btf/btf.rs @@ -135,7 +135,7 @@ pub enum BtfError { #[source] io_error: std::io::Error, /// The error log produced by the kernel verifier. - verifier_log: Cow<'static, str>, + verifier_log: String, }, /// offset not found for symbol diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 3ca6854c..7aad3bc9 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -67,7 +67,6 @@ pub mod xdp; use libc::ENOSPC; use procfs::KernelVersion; use std::{ - borrow::Cow, ffi::CString, io, os::unix::io::{AsRawFd, RawFd}, @@ -143,7 +142,7 @@ pub enum ProgramError { #[source] io_error: io::Error, /// The error log produced by the kernel verifier. - verifier_log: Cow<'static, str>, + verifier_log: String, }, /// A syscall failed. diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index 5a7dc3c5..f16dc4be 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -1,5 +1,4 @@ use std::{ - borrow::Cow, cmp::{self, min}, ffi::{CStr, CString}, io, @@ -993,13 +992,10 @@ pub(crate) fn bpf_prog_get_next_id(id: u32) -> Result, (c_long, io:: } } -pub(crate) fn retry_with_verifier_logs( +pub(crate) fn retry_with_verifier_logs( max_retries: usize, - f: F, -) -> (SysResult, Cow<'static, str>) -where - F: Fn(&mut [u8]) -> SysResult, -{ + f: impl Fn(&mut [u8]) -> SysResult, +) -> (SysResult, String) { const MIN_LOG_BUF_SIZE: usize = 1024 * 10; const MAX_LOG_BUF_SIZE: usize = (std::u32::MAX >> 8) as usize; @@ -1023,11 +1019,7 @@ where if let Some(pos) = log_buf.iter().position(|b| *b == 0) { log_buf.truncate(pos); } - let log_buf = if log_buf.is_empty() { - "none".into() - } else { - String::from_utf8(log_buf).unwrap().into() - }; + let log_buf = String::from_utf8(log_buf).unwrap(); break (ret, log_buf); } From cc2bc0acc183f178292d630789031aed0634f878 Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Mon, 10 Jul 2023 21:35:20 -0400 Subject: [PATCH 2/5] Remove procfs dependency --- aya/Cargo.toml | 1 - aya/src/maps/mod.rs | 2 +- aya/src/programs/cgroup_device.rs | 2 +- aya/src/programs/cgroup_skb.rs | 2 +- aya/src/programs/cgroup_sock.rs | 2 +- aya/src/programs/cgroup_sock_addr.rs | 2 +- aya/src/programs/cgroup_sockopt.rs | 2 +- aya/src/programs/cgroup_sysctl.rs | 2 +- aya/src/programs/mod.rs | 2 +- aya/src/programs/probe.rs | 2 +- aya/src/programs/xdp.rs | 2 +- aya/src/sys/bpf.rs | 2 +- aya/src/util.rs | 66 ++++++++++++++++++- test/integration-test/Cargo.toml | 1 - .../integration-test/tests/btf_relocations.rs | 3 +- test/integration-test/tests/load.rs | 2 +- test/integration-test/tests/smoke.rs | 3 +- 17 files changed, 77 insertions(+), 21 deletions(-) diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 2abcfc47..1a6faf5d 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -31,7 +31,6 @@ tokio = { version = "1.24.0", features = [ "rt-multi-thread", "net", ], optional = true } -procfs = { version = "0.15.1", default-features = false } [dev-dependencies] futures = { version = "0.3.12", default-features = false, features = ["std"] } diff --git a/aya/src/maps/mod.rs b/aya/src/maps/mod.rs index 3961c212..2332e1f5 100644 --- a/aya/src/maps/mod.rs +++ b/aya/src/maps/mod.rs @@ -47,9 +47,9 @@ use std::{ ptr, }; +use crate::util::KernelVersion; use libc::{getrlimit, rlimit, RLIMIT_MEMLOCK, RLIM_INFINITY}; use log::warn; -use procfs::KernelVersion; use thiserror::Error; use crate::{ diff --git a/aya/src/programs/cgroup_device.rs b/aya/src/programs/cgroup_device.rs index b1a8e39d..e3580b28 100644 --- a/aya/src/programs/cgroup_device.rs +++ b/aya/src/programs/cgroup_device.rs @@ -1,6 +1,6 @@ //! Cgroup device programs. -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::os::fd::{AsRawFd, RawFd}; use crate::{ diff --git a/aya/src/programs/cgroup_skb.rs b/aya/src/programs/cgroup_skb.rs index a76bb14a..f67b56fe 100644 --- a/aya/src/programs/cgroup_skb.rs +++ b/aya/src/programs/cgroup_skb.rs @@ -1,6 +1,6 @@ //! Cgroup skb programs. -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::{ hash::Hash, os::fd::{AsRawFd, RawFd}, diff --git a/aya/src/programs/cgroup_sock.rs b/aya/src/programs/cgroup_sock.rs index 19ac6cf8..9d66f9aa 100644 --- a/aya/src/programs/cgroup_sock.rs +++ b/aya/src/programs/cgroup_sock.rs @@ -2,7 +2,7 @@ pub use aya_obj::programs::CgroupSockAttachType; -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::{ hash::Hash, os::fd::{AsRawFd, RawFd}, diff --git a/aya/src/programs/cgroup_sock_addr.rs b/aya/src/programs/cgroup_sock_addr.rs index 72eca7ec..045a40d2 100644 --- a/aya/src/programs/cgroup_sock_addr.rs +++ b/aya/src/programs/cgroup_sock_addr.rs @@ -2,7 +2,7 @@ pub use aya_obj::programs::CgroupSockAddrAttachType; -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::{ hash::Hash, os::fd::{AsRawFd, RawFd}, diff --git a/aya/src/programs/cgroup_sockopt.rs b/aya/src/programs/cgroup_sockopt.rs index 9d8b314a..95b89dd7 100644 --- a/aya/src/programs/cgroup_sockopt.rs +++ b/aya/src/programs/cgroup_sockopt.rs @@ -2,7 +2,7 @@ pub use aya_obj::programs::CgroupSockoptAttachType; -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::{ hash::Hash, os::fd::{AsRawFd, RawFd}, diff --git a/aya/src/programs/cgroup_sysctl.rs b/aya/src/programs/cgroup_sysctl.rs index c3ce1011..3cd20195 100644 --- a/aya/src/programs/cgroup_sysctl.rs +++ b/aya/src/programs/cgroup_sysctl.rs @@ -1,6 +1,6 @@ //! Cgroup sysctl programs. -use procfs::KernelVersion; +use crate::util::KernelVersion; use std::{ hash::Hash, os::fd::{AsRawFd, RawFd}, diff --git a/aya/src/programs/mod.rs b/aya/src/programs/mod.rs index 7aad3bc9..68ebe748 100644 --- a/aya/src/programs/mod.rs +++ b/aya/src/programs/mod.rs @@ -64,8 +64,8 @@ pub mod uprobe; mod utils; pub mod xdp; +use crate::util::KernelVersion; use libc::ENOSPC; -use procfs::KernelVersion; use std::{ ffi::CString, io, diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index c6320e1a..98543149 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -1,5 +1,5 @@ +use crate::util::KernelVersion; use libc::pid_t; -use procfs::KernelVersion; use std::{ fs::{self, OpenOptions}, io::{self, Write}, diff --git a/aya/src/programs/xdp.rs b/aya/src/programs/xdp.rs index 01843928..a85c87c2 100644 --- a/aya/src/programs/xdp.rs +++ b/aya/src/programs/xdp.rs @@ -1,8 +1,8 @@ //! eXpress Data Path (XDP) programs. +use crate::util::KernelVersion; use bitflags; use libc::if_nametoindex; -use procfs::KernelVersion; use std::{convert::TryFrom, ffi::CString, hash::Hash, io, mem, os::unix::io::RawFd}; use thiserror::Error; diff --git a/aya/src/sys/bpf.rs b/aya/src/sys/bpf.rs index f16dc4be..5809d4c6 100644 --- a/aya/src/sys/bpf.rs +++ b/aya/src/sys/bpf.rs @@ -7,12 +7,12 @@ use std::{ slice, }; +use crate::util::KernelVersion; use libc::{c_char, c_long, close, ENOENT, ENOSPC}; use obj::{ maps::{bpf_map_def, LegacyMap}, BpfSectionKind, }; -use procfs::KernelVersion; use crate::{ generated::{ diff --git a/aya/src/util.rs b/aya/src/util.rs index b0bb3781..33e99a86 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -3,8 +3,10 @@ use std::{ collections::BTreeMap, ffi::CString, fs::{self, File}, - io::{self, BufReader}, - mem, slice, + io::{self, BufRead, BufReader}, + mem, + num::ParseIntError, + slice, str::FromStr, }; @@ -15,7 +17,65 @@ use crate::{ use libc::{if_nametoindex, sysconf, _SC_PAGESIZE}; -use io::BufRead; +/// Represents a kernel version, in major.minor.release version. +// Adapted from https://docs.rs/procfs/latest/procfs/sys/kernel/struct.Version.html. +#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd)] +pub struct KernelVersion { + pub(crate) major: u8, + pub(crate) minor: u8, + pub(crate) patch: u16, +} + +impl KernelVersion { + /// Constructor. + pub fn new(major: u8, minor: u8, patch: u16) -> Self { + Self { + major, + minor, + patch, + } + } + + /// Returns the kernel version of the currently running kernel. + /// + /// This is taken from `/proc/sys/kernel/osrelease`; + pub fn current() -> Result { + let s = + fs::read_to_string("/proc/sys/kernel/osrelease").map_err(|err| format!("{err:?}"))?; + let s = s.as_str(); + + 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("Missing major version component")?; + let minor = kernel_split + .next() + .ok_or("Missing minor version component")?; + let patch = kernel_split + .next() + .ok_or("Missing patch version component")?; + + let major = major + .parse() + .map_err(|ParseIntError { .. }| "Failed to parse major version")?; + let minor = minor + .parse() + .map_err(|ParseIntError { .. }| "Failed to parse minor version")?; + let patch = patch + .parse() + .map_err(|ParseIntError { .. }| "Failed to parse patch version")?; + + Ok(Self::new(major, minor, patch)) + } +} const ONLINE_CPUS: &str = "/sys/devices/system/cpu/online"; pub(crate) const POSSIBLE_CPUS: &str = "/sys/devices/system/cpu/possible"; diff --git a/test/integration-test/Cargo.toml b/test/integration-test/Cargo.toml index 36f8270b..09770325 100644 --- a/test/integration-test/Cargo.toml +++ b/test/integration-test/Cargo.toml @@ -12,7 +12,6 @@ aya-obj = { path = "../../aya-obj" } libc = { version = "0.2.105" } log = "0.4" object = { version = "0.31", default-features = false, features = ["std", "read_core", "elf"] } -procfs = "0.15.1" rbpf = "0.2.0" tempfile = "3.3.0" tokio = { version = "1.24", features = ["rt", "rt-multi-thread", "sync", "time"] } diff --git a/test/integration-test/tests/btf_relocations.rs b/test/integration-test/tests/btf_relocations.rs index 069bc76c..37a138bf 100644 --- a/test/integration-test/tests/btf_relocations.rs +++ b/test/integration-test/tests/btf_relocations.rs @@ -1,9 +1,8 @@ use anyhow::{bail, Context as _, Result}; -use procfs::KernelVersion; use std::{path::PathBuf, process::Command, thread::sleep, time::Duration}; use tempfile::TempDir; -use aya::{maps::Array, programs::TracePoint, BpfLoader, Btf, Endianness}; +use aya::{maps::Array, programs::TracePoint, util::KernelVersion, BpfLoader, Btf, Endianness}; // In the tests below we often use values like 0xAAAAAAAA or -0x7AAAAAAA. Those values have no // special meaning, they just have "nice" bit patterns that can be helpful while debugging. diff --git a/test/integration-test/tests/load.rs b/test/integration-test/tests/load.rs index 47a851cf..3f35e06e 100644 --- a/test/integration-test/tests/load.rs +++ b/test/integration-test/tests/load.rs @@ -1,4 +1,3 @@ -use procfs::KernelVersion; use std::{convert::TryInto as _, thread, time}; use aya::{ @@ -8,6 +7,7 @@ use aya::{ links::{FdLink, PinnedLink}, loaded_programs, KProbe, TracePoint, Xdp, XdpFlags, }, + util::KernelVersion, Bpf, }; diff --git a/test/integration-test/tests/smoke.rs b/test/integration-test/tests/smoke.rs index 2bc10ff4..304772e8 100644 --- a/test/integration-test/tests/smoke.rs +++ b/test/integration-test/tests/smoke.rs @@ -1,8 +1,7 @@ -use procfs::KernelVersion; - use aya::{ include_bytes_aligned, programs::{Extension, Xdp, XdpFlags}, + util::KernelVersion, Bpf, BpfLoader, }; From 6e570f0f14e615ccd0eeb80dfb68f3674f6ee74a Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 11 Jul 2023 10:43:49 -0400 Subject: [PATCH 3/5] Rewrite kernel version logic This restores and enhances the logic originally added in #579. --- aya/Cargo.toml | 1 + aya/src/util.rs | 146 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 107 insertions(+), 40 deletions(-) diff --git a/aya/Cargo.toml b/aya/Cargo.toml index 1a6faf5d..e91da921 100644 --- a/aya/Cargo.toml +++ b/aya/Cargo.toml @@ -24,6 +24,7 @@ object = { version = "0.31", default-features = false, features = [ "elf", ] } parking_lot = { version = "0.12.0", features = ["send_guard"] } +text_io = "0.1.12" thiserror = "1" tokio = { version = "1.24.0", features = [ "macros", diff --git a/aya/src/util.rs b/aya/src/util.rs index 33e99a86..4588774e 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -1,12 +1,10 @@ //! Utility functions. use std::{ collections::BTreeMap, - ffi::CString, + ffi::{CStr, CString}, fs::{self, File}, io::{self, BufRead, BufReader}, - mem, - num::ParseIntError, - slice, + mem, slice, str::FromStr, }; @@ -15,7 +13,7 @@ use crate::{ Pod, }; -use libc::{if_nametoindex, sysconf, _SC_PAGESIZE}; +use libc::{if_nametoindex, sysconf, uname, utsname, _SC_PAGESIZE}; /// Represents a kernel version, in major.minor.release version. // Adapted from https://docs.rs/procfs/latest/procfs/sys/kernel/struct.Version.html. @@ -37,43 +35,111 @@ impl KernelVersion { } /// Returns the kernel version of the currently running kernel. - /// - /// This is taken from `/proc/sys/kernel/osrelease`; pub fn current() -> Result { - let s = - fs::read_to_string("/proc/sys/kernel/osrelease").map_err(|err| format!("{err:?}"))?; - let s = s.as_str(); - - 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 kernel_version = Self::get_kernel_version(); + + // The kernel version is clamped to 4.19.255 on kernels 4.19.222 and above. + // + // See https://github.com/torvalds/linux/commit/a256aac. + const CLAMPED_KERNEL_MAJOR: u8 = 4; + const CLAMPED_KERNEL_MINOR: u8 = 19; + if let Ok(Self { + major: CLAMPED_KERNEL_MAJOR, + minor: CLAMPED_KERNEL_MINOR, + patch: 222.., + }) = kernel_version + { + return Ok(Self::new(CLAMPED_KERNEL_MAJOR, CLAMPED_KERNEL_MINOR, 255)); + } + + kernel_version + } + + // This is ported from https://github.com/torvalds/linux/blob/3f01e9f/tools/lib/bpf/libbpf_probes.c#L21-L101. + + fn get_ubuntu_kernel_version() -> Result, String> { + const UBUNTU_KVER_FILE: &str = "/proc/version_signature"; + let s = match fs::read(UBUNTU_KVER_FILE) { + Ok(s) => s, + Err(e) => { + if e.kind() == io::ErrorKind::NotFound { + return Ok(None); + } + return Err(format!("failed to read {}: {}", UBUNTU_KVER_FILE, e)); + } + }; + (|| { + let ubuntu: String; + let ubuntu_version: String; + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(s.iter().copied() => "{} {} {}.{}.{}\n", ubuntu, ubuntu_version, major, minor, patch); + Ok(Some(Self::new(major, minor, patch))) + })().map_err(|e: text_io::Error| format!("failed to parse {:?}: {}", s, e)) + } + + fn get_debian_kernel_version(info: &utsname) -> Result, String> { + // Safety: man 2 uname: + // + // The length of the arrays in a struct utsname is unspecified (see NOTES); the fields are + // terminated by a null byte ('\0'). + let p = unsafe { CStr::from_ptr(info.version.as_ptr()) }; + let p = p + .to_str() + .map_err(|e| format!("failed to parse version: {}", e))?; + let p = match p.split_once("Debian ") { + Some((_prefix, suffix)) => suffix, + None => return Ok(None), + }; + (|| { + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); + Ok(Some(Self::new(major, minor, patch))) + })() + .map_err(|e: text_io::Error| format!("failed to parse {}: {}", p, e)) + } + + fn get_kernel_version() -> Result { + if let Some(v) = Self::get_ubuntu_kernel_version()? { + return Ok(v); + } + + let mut info = unsafe { mem::zeroed::() }; + if unsafe { uname(&mut info) } != 0 { + return Err(format!( + "failed to get kernel version: {}", + io::Error::last_os_error() + )); + } + + if let Some(v) = Self::get_debian_kernel_version(&info)? { + return Ok(v); + } + + // Safety: man 2 uname: + // + // The length of the arrays in a struct utsname is unspecified (see NOTES); the fields are + // terminated by a null byte ('\0'). + let p = unsafe { CStr::from_ptr(info.release.as_ptr()) }; + let p = p + .to_str() + .map_err(|e| format!("failed to parse release: {}", e))?; + // Unlike sscanf, text_io::try_scan! does not stop at the first non-matching character. + let p = match p.split_once(|c: char| c != '.' && !c.is_ascii_digit()) { + Some((prefix, _suffix)) => prefix, + None => p, }; - let mut kernel_split = kernel.split('.'); - - let major = kernel_split - .next() - .ok_or("Missing major version component")?; - let minor = kernel_split - .next() - .ok_or("Missing minor version component")?; - let patch = kernel_split - .next() - .ok_or("Missing patch version component")?; - - let major = major - .parse() - .map_err(|ParseIntError { .. }| "Failed to parse major version")?; - let minor = minor - .parse() - .map_err(|ParseIntError { .. }| "Failed to parse minor version")?; - let patch = patch - .parse() - .map_err(|ParseIntError { .. }| "Failed to parse patch version")?; - - Ok(Self::new(major, minor, patch)) + (|| { + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); + Ok(Self::new(major, minor, patch)) + })() + .map_err(|e: text_io::Error| format!("failed to parse {}: {}", p, e)) } } From 6bceb1c3da2d0d71842073a2503810a666ef3caf Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 11 Jul 2023 16:52:06 -0400 Subject: [PATCH 4/5] Invert comparison Incorrectly inverted in b611038d5b41a45ca70553550dbdef9aa1fd117c. --- aya/src/programs/probe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aya/src/programs/probe.rs b/aya/src/programs/probe.rs index 98543149..80a5c088 100644 --- a/aya/src/programs/probe.rs +++ b/aya/src/programs/probe.rs @@ -50,7 +50,7 @@ pub(crate) fn attach>( ) -> Result { // https://github.com/torvalds/linux/commit/e12f03d7031a977356e3d7b75a68c2185ff8d155 // Use debugfs to create probe - if KernelVersion::current().unwrap() >= KernelVersion::new(4, 17, 0) { + if KernelVersion::current().unwrap() < KernelVersion::new(4, 17, 0) { let (fd, event_alias) = create_as_trace_point(kind, fn_name, offset, pid)?; let link = T::from(perf_attach_debugfs( program_data.fd_or_err()?, From a1e0130387390c148fc035ed1ae6b5665be4a96f Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Tue, 11 Jul 2023 23:52:18 -0400 Subject: [PATCH 5/5] Type-erase KernelVersion::current error --- aya/src/util.rs | 84 +++++++++++++++++++++++++------------------------ 1 file changed, 43 insertions(+), 41 deletions(-) diff --git a/aya/src/util.rs b/aya/src/util.rs index 4588774e..aaca0f5f 100644 --- a/aya/src/util.rs +++ b/aya/src/util.rs @@ -1,11 +1,12 @@ //! Utility functions. use std::{ collections::BTreeMap, + error::Error, ffi::{CStr, CString}, fs::{self, File}, io::{self, BufRead, BufReader}, mem, slice, - str::FromStr, + str::{FromStr, Utf8Error}, }; use crate::{ @@ -24,6 +25,20 @@ pub struct KernelVersion { pub(crate) patch: u16, } +/// An error encountered while fetching the current kernel version. +#[derive(thiserror::Error, Debug)] +pub enum CurrentKernelVersionError { + /// The kernel version string could not be read. + #[error("failed to read kernel version")] + IOError(#[from] io::Error), + /// The kernel version string could not be parsed. + #[error("failed to parse kernel version")] + ParseError(#[from] text_io::Error), + /// The kernel version string was not valid UTF-8. + #[error("kernel version string is not valid UTF-8")] + Utf8Error(#[from] Utf8Error), +} + impl KernelVersion { /// Constructor. pub fn new(major: u8, minor: u8, patch: u16) -> Self { @@ -35,7 +50,7 @@ impl KernelVersion { } /// Returns the kernel version of the currently running kernel. - pub fn current() -> Result { + pub fn current() -> Result { let kernel_version = Self::get_kernel_version(); // The kernel version is clamped to 4.19.255 on kernels 4.19.222 and above. @@ -57,7 +72,7 @@ impl KernelVersion { // This is ported from https://github.com/torvalds/linux/blob/3f01e9f/tools/lib/bpf/libbpf_probes.c#L21-L101. - fn get_ubuntu_kernel_version() -> Result, String> { + fn get_ubuntu_kernel_version() -> Result, CurrentKernelVersionError> { const UBUNTU_KVER_FILE: &str = "/proc/version_signature"; let s = match fs::read(UBUNTU_KVER_FILE) { Ok(s) => s, @@ -65,54 +80,46 @@ impl KernelVersion { if e.kind() == io::ErrorKind::NotFound { return Ok(None); } - return Err(format!("failed to read {}: {}", UBUNTU_KVER_FILE, e)); + return Err(e.into()); } }; - (|| { - let ubuntu: String; - let ubuntu_version: String; - let major: u8; - let minor: u8; - let patch: u16; - text_io::try_scan!(s.iter().copied() => "{} {} {}.{}.{}\n", ubuntu, ubuntu_version, major, minor, patch); - Ok(Some(Self::new(major, minor, patch))) - })().map_err(|e: text_io::Error| format!("failed to parse {:?}: {}", s, e)) + let ubuntu: String; + let ubuntu_version: String; + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(s.iter().copied() => "{} {} {}.{}.{}\n", ubuntu, ubuntu_version, major, minor, patch); + Ok(Some(Self::new(major, minor, patch))) } - fn get_debian_kernel_version(info: &utsname) -> Result, String> { + fn get_debian_kernel_version( + info: &utsname, + ) -> Result, CurrentKernelVersionError> { // Safety: man 2 uname: // // The length of the arrays in a struct utsname is unspecified (see NOTES); the fields are // terminated by a null byte ('\0'). let p = unsafe { CStr::from_ptr(info.version.as_ptr()) }; - let p = p - .to_str() - .map_err(|e| format!("failed to parse version: {}", e))?; + let p = p.to_str()?; let p = match p.split_once("Debian ") { Some((_prefix, suffix)) => suffix, None => return Ok(None), }; - (|| { - let major: u8; - let minor: u8; - let patch: u16; - text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); - Ok(Some(Self::new(major, minor, patch))) - })() - .map_err(|e: text_io::Error| format!("failed to parse {}: {}", p, e)) + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); + Ok(Some(Self::new(major, minor, patch))) } - fn get_kernel_version() -> Result { + fn get_kernel_version() -> Result { if let Some(v) = Self::get_ubuntu_kernel_version()? { return Ok(v); } let mut info = unsafe { mem::zeroed::() }; if unsafe { uname(&mut info) } != 0 { - return Err(format!( - "failed to get kernel version: {}", - io::Error::last_os_error() - )); + return Err(io::Error::last_os_error().into()); } if let Some(v) = Self::get_debian_kernel_version(&info)? { @@ -124,22 +131,17 @@ impl KernelVersion { // The length of the arrays in a struct utsname is unspecified (see NOTES); the fields are // terminated by a null byte ('\0'). let p = unsafe { CStr::from_ptr(info.release.as_ptr()) }; - let p = p - .to_str() - .map_err(|e| format!("failed to parse release: {}", e))?; + let p = p.to_str()?; // Unlike sscanf, text_io::try_scan! does not stop at the first non-matching character. let p = match p.split_once(|c: char| c != '.' && !c.is_ascii_digit()) { Some((prefix, _suffix)) => prefix, None => p, }; - (|| { - let major: u8; - let minor: u8; - let patch: u16; - text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); - Ok(Self::new(major, minor, patch)) - })() - .map_err(|e: text_io::Error| format!("failed to parse {}: {}", p, e)) + let major: u8; + let minor: u8; + let patch: u16; + text_io::try_scan!(p.bytes() => "{}.{}.{}", major, minor, patch); + Ok(Self::new(major, minor, patch)) } }