use crate::utils::*;
use num_enum::TryFromPrimitive;
use std::convert::TryFrom;
use std::fmt;
use std::str::FromStr;
use std::time::Duration;
pub(crate) const DEST: &str = "org.freedesktop.UDisks2.Drive.Ata";
pub(crate) const UPDATE: &str = "SmartUpdate";
pub(crate) const GET_ATTRS: &str = "SmartGetAttributes";
pub(crate) const ENABLED: &str = "SmartEnabled";
pub(crate) const SUPPORTED: &str = "SmartSupported";
pub(crate) const UPDATED: &str = "SmartUpdated";
pub(crate) const FAILING: &str = "SmartFailing";
pub(crate) const TIME_POWER_ON: &str = "SmartPowerOnSeconds";
pub(crate) const TEMPERATURE: &str = "SmartTemperature";
pub(crate) const FAILING_ATTRS_COUNT: &str = "SmartNumAttributesFailing";
pub(crate) const PAST_FAILING_ATTRS_COUNT: &str = "SmartNumAttributesFailedInThePast";
pub(crate) const BAD_SECTORS: &str = "SmartNumBadSectors";
pub(crate) const STATUS: &str = "SmartSelftestStatus";
pub(crate) type RawSmartAttribute = (u8, String, u16, i32, i32, i32, i64, i32, KeyVariant);
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
#[non_exhaustive]
pub enum SmartStatus {
Success,
Aborted,
Interrupted,
Fatal,
UnknownError,
ElectricalError,
ServoError,
ReadError,
HandlingError,
InProgress,
Unknown,
}
impl FromStr for SmartStatus {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"success" => Ok(SmartStatus::Success),
"aborted" => Ok(SmartStatus::Aborted),
"interrupted" => Ok(SmartStatus::Interrupted),
"fatal" => Ok(SmartStatus::Fatal),
"error_unknown" => Ok(SmartStatus::UnknownError),
"error_electrical" => Ok(SmartStatus::ElectricalError),
"error_servo" => Ok(SmartStatus::ServoError),
"error_read" => Ok(SmartStatus::ReadError),
"error_handling" => Ok(SmartStatus::HandlingError),
"inprogress" => Ok(SmartStatus::InProgress),
_ => Err(()),
}
}
}
#[derive(Clone, Debug)]
pub enum SmartValue {
NotSupported,
NotEnabled,
NotUpdated,
Enabled(SmartData),
}
#[derive(Clone, Debug)]
pub struct SmartData {
pub attributes: Vec<SmartAttribute>,
pub updated: u64,
pub failing: bool,
pub time_powered_on: u64,
pub temperature: f64,
pub failing_attrs_count: i32,
pub past_failing_attrs_count: i32,
pub bad_sectors: i64,
pub status: SmartStatus,
}
#[derive(Debug, Eq, PartialEq, TryFromPrimitive, Copy, Clone, Hash)]
#[repr(u8)]
#[non_exhaustive]
pub enum PrettyUnit {
Dimensionless = 1,
Milliseconds,
Sectors,
Millikelvin,
}
#[derive(Eq, PartialEq, Copy, Clone, Hash)]
pub struct PrettyValue {
pub value: i64,
pub unit: PrettyUnit,
}
impl fmt::Debug for PrettyValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} / ", self)?;
f.debug_struct("PrettyValue")
.field("value", &self.value)
.field("unit", &self.unit)
.finish()
}
}
impl fmt::Display for PrettyValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.unit {
PrettyUnit::Dimensionless => write!(f, "{}", self.value),
PrettyUnit::Milliseconds => write!(f, "{:?}", Duration::from_millis(self.value as u64)),
PrettyUnit::Sectors => write!(f, "{} sectors", self.value),
PrettyUnit::Millikelvin => {
write!(f, "{:.1} degrees C", self.value as f32 / 1000. - 273.15)
}
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum SmartAssessment {
Failing,
FailedInPast,
Ok,
}
#[derive(Clone, Debug)]
pub struct SmartAttribute {
pub id: u8,
pub name: String,
pub flags: u16,
pub normalized: i32,
pub worst: i32,
pub threshold: i32,
pub pretty: Option<PrettyValue>,
}
impl SmartAttribute {
pub fn pre_fail(&self) -> bool {
self.flags & 0x01 > 0
}
pub fn online(&self) -> bool {
self.flags & 0x02 > 0
}
pub fn performance(&self) -> bool {
self.flags & 0x04 > 0
}
pub fn error_rate(&self) -> bool {
self.flags & 0x08 > 0
}
pub fn event_count(&self) -> bool {
self.flags & 0x10 > 0
}
pub fn self_preserving(&self) -> bool {
self.flags & 0x20 > 0
}
pub fn assessment(&self) -> SmartAssessment {
if self.normalized > 0 && self.threshold > 0 && self.normalized <= self.threshold {
SmartAssessment::Failing
} else if self.worst > 0 && self.threshold > 0 && self.worst <= self.threshold {
SmartAssessment::FailedInPast
} else {
SmartAssessment::Ok
}
}
}
impl From<RawSmartAttribute> for SmartAttribute {
fn from(
(id, name, flags, value, worst, threshold, pretty_value, pretty_unit, _expansion): RawSmartAttribute,
) -> Self {
let pretty = PrettyUnit::try_from(pretty_unit as u8)
.map(|unit| PrettyValue {
value: pretty_value,
unit,
})
.ok();
SmartAttribute {
id,
name,
flags,
normalized: value,
worst,
threshold,
pretty,
}
}
}