123 lines
3.8 KiB
Rust
123 lines
3.8 KiB
Rust
|
|
use std::fmt;
|
||
|
|
|
||
|
|
pub const MINIMUM_KERNEL_MAJOR: u64 = 6;
|
||
|
|
pub const MINIMUM_KERNEL_MINOR: u64 = 9;
|
||
|
|
|
||
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||
|
|
pub struct PlatformObservation<'a> {
|
||
|
|
pub operating_system: &'a str,
|
||
|
|
pub architecture: &'a str,
|
||
|
|
pub kernel_release: &'a str,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||
|
|
pub enum PlatformRefusal {
|
||
|
|
OperatingSystem(String),
|
||
|
|
Architecture(String),
|
||
|
|
KernelRelease(String),
|
||
|
|
KernelFloor { major: u64, minor: u64 },
|
||
|
|
}
|
||
|
|
|
||
|
|
impl fmt::Display for PlatformRefusal {
|
||
|
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||
|
|
match self {
|
||
|
|
Self::OperatingSystem(value) => {
|
||
|
|
write!(formatter, "unsupported operating system {value}")
|
||
|
|
}
|
||
|
|
Self::Architecture(value) => write!(formatter, "unsupported architecture {value}"),
|
||
|
|
Self::KernelRelease(value) => write!(formatter, "invalid Linux kernel release {value}"),
|
||
|
|
Self::KernelFloor { major, minor } => write!(
|
||
|
|
formatter,
|
||
|
|
"Linux kernel {major}.{minor} is below the required 6.9 floor"
|
||
|
|
),
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
impl std::error::Error for PlatformRefusal {}
|
||
|
|
|
||
|
|
/// # Errors
|
||
|
|
/// Refuses unsupported operating systems, architectures, and kernel releases.
|
||
|
|
pub fn check_platform(observation: &PlatformObservation<'_>) -> Result<(), PlatformRefusal> {
|
||
|
|
if observation.operating_system != "linux" {
|
||
|
|
return Err(PlatformRefusal::OperatingSystem(
|
||
|
|
observation.operating_system.into(),
|
||
|
|
));
|
||
|
|
}
|
||
|
|
if observation.architecture != "x86_64" {
|
||
|
|
return Err(PlatformRefusal::Architecture(
|
||
|
|
observation.architecture.into(),
|
||
|
|
));
|
||
|
|
}
|
||
|
|
let (major, minor) = parse_kernel_release(observation.kernel_release)?;
|
||
|
|
if (major, minor) < (MINIMUM_KERNEL_MAJOR, MINIMUM_KERNEL_MINOR) {
|
||
|
|
return Err(PlatformRefusal::KernelFloor { major, minor });
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
}
|
||
|
|
|
||
|
|
/// # Errors
|
||
|
|
/// Refuses releases without numeric major and minor components.
|
||
|
|
pub fn parse_kernel_release(release: &str) -> Result<(u64, u64), PlatformRefusal> {
|
||
|
|
let mut components = release.split('.');
|
||
|
|
let major = components
|
||
|
|
.next()
|
||
|
|
.and_then(|value| value.parse().ok())
|
||
|
|
.ok_or_else(|| PlatformRefusal::KernelRelease(release.into()))?;
|
||
|
|
let minor = components
|
||
|
|
.next()
|
||
|
|
.and_then(|value| {
|
||
|
|
value
|
||
|
|
.split_once('-')
|
||
|
|
.map_or(value, |(number, _)| number)
|
||
|
|
.parse()
|
||
|
|
.ok()
|
||
|
|
})
|
||
|
|
.ok_or_else(|| PlatformRefusal::KernelRelease(release.into()))?;
|
||
|
|
Ok((major, minor))
|
||
|
|
}
|
||
|
|
|
||
|
|
#[cfg(test)]
|
||
|
|
mod tests {
|
||
|
|
use super::{PlatformObservation, PlatformRefusal, check_platform};
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn accepts_floor_and_newer_linux_x86_64() {
|
||
|
|
for release in ["6.9.0", "6.9.12-custom", "6.10.0", "7.0"] {
|
||
|
|
check_platform(&PlatformObservation {
|
||
|
|
operating_system: "linux",
|
||
|
|
architecture: "x86_64",
|
||
|
|
kernel_release: release,
|
||
|
|
})
|
||
|
|
.unwrap();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#[test]
|
||
|
|
fn rejects_older_kernel_and_other_platforms() {
|
||
|
|
let old = check_platform(&PlatformObservation {
|
||
|
|
operating_system: "linux",
|
||
|
|
architecture: "x86_64",
|
||
|
|
kernel_release: "6.8.14",
|
||
|
|
});
|
||
|
|
assert_eq!(
|
||
|
|
old,
|
||
|
|
Err(PlatformRefusal::KernelFloor { major: 6, minor: 8 })
|
||
|
|
);
|
||
|
|
|
||
|
|
for observation in [
|
||
|
|
PlatformObservation {
|
||
|
|
operating_system: "freebsd",
|
||
|
|
architecture: "x86_64",
|
||
|
|
kernel_release: "14.0",
|
||
|
|
},
|
||
|
|
PlatformObservation {
|
||
|
|
operating_system: "linux",
|
||
|
|
architecture: "aarch64",
|
||
|
|
kernel_release: "6.9.0",
|
||
|
|
},
|
||
|
|
] {
|
||
|
|
assert!(check_platform(&observation).is_err());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|