use std::{
fmt, fs,
path::{Path, PathBuf},
};
use super::{DeviceTempProber, Drive, DriveTempProbeMethod, ProberError, Temp};
pub(crate) struct Method;
impl DriveTempProbeMethod for Method {
type Prober = Prober;
fn prober(&self, drive: &Drive) -> Result<Prober, ProberError> {
#[expect(clippy::unwrap_used)] let drive_name = drive.dev_path.file_name().unwrap();
let hwmon_dir = Path::new("/sys/block/")
.join(drive_name)
.join("../../hwmon");
if !hwmon_dir.is_dir() {
return Err(ProberError::Unsupported(format!(
"{hwmon_dir:?} does not exist"
)));
}
for hwmon_subdir_entry in fs::read_dir(&hwmon_dir)
.map_err(|e| ProberError::Other(e.into()))?
.map_while(Result::ok)
.filter(|e| e.file_type().is_ok_and(|t| t.is_dir()))
{
let hwmon_subdir = hwmon_subdir_entry.path();
let name_file = hwmon_subdir.join("name");
let name = fs::read_to_string(&name_file)
.map_err(|e| ProberError::Other(e.into()))?
.trim_end()
.to_owned();
if name == "drivetemp" {
let input_path = hwmon_subdir.join("temp1_input");
if !input_path.is_file() {
return Err(ProberError::Other(anyhow::anyhow!(
"{input_path:?} does not exist"
)));
}
return Ok(Prober { input_path });
}
}
Err(ProberError::Unsupported(format!(
"No drivetemp hwmon found in {hwmon_dir:?}"
)))
}
fn supports_probing_sleeping(&self) -> bool {
true
}
}
impl fmt::Display for Method {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
write!(f, "native Linux drivetemp")
}
}
pub(crate) struct Prober {
input_path: PathBuf,
}
impl DeviceTempProber for Prober {
fn probe_temp(&mut self) -> anyhow::Result<Temp> {
Ok(f64::from(
fs::read_to_string(&self.input_path)?
.trim_end()
.parse::<u32>()?,
) / 1000.0)
}
}
#[cfg(test)]
mod tests {
use std::io::Write as _;
use float_cmp::approx_eq;
use super::*;
#[test]
fn test_probe_temp() {
let mut input_file = tempfile::NamedTempFile::new().unwrap();
let mut prober = Prober {
input_path: input_file.path().to_owned(),
};
input_file.write_all("54321\n".as_bytes()).unwrap();
assert!(approx_eq!(f64, prober.probe_temp().unwrap(), 54.321));
}
}