Add root syspath and hwmon functionality

This commit is contained in:
NGnius 2023-07-20 19:28:59 -04:00
parent 2e1d24250f
commit 1391e2fb2c
4 changed files with 253 additions and 5 deletions

179
src/hwmon.rs Normal file
View file

@ -0,0 +1,179 @@
use std::path::{Path, PathBuf};
use std::convert::AsRef;
use std::io::Result as IoResult;
const HWMON_DIR_PATH: &'static str = "sys/class/hwmon/";
/// Attribute representation.
/// Attribute files are usually in the format `<type><number>_<item>`.
#[derive(Clone, Copy)]
pub struct HwMonAttribute {
inner: HwMonAttributeInner,
}
#[derive(Clone, Copy)]
enum HwMonAttributeInner {
Name,
Standard {
ty: HwMonAttributeType,
number: u64,
item: HwMonAttributeItem,
},
Uevent,
}
/// Attribute type in the format `<type><number>_<item>`
#[derive(Clone, Copy)]
pub enum HwMonAttributeType {
/// Voltage
In,
/// Temperature
Temp,
/// Fan
Fan,
/// Current
Curr,
}
impl HwMonAttributeType {
fn to_attr_str(&self) -> &str {
match self {
Self::In => "in",
Self::Temp => "out",
Self::Fan => "fan",
Self::Curr => "curr",
}
}
}
/// Attribute item in the format `<type><number>_<item>`
#[derive(Clone, Copy)]
pub enum HwMonAttributeItem {
/// Input
Input,
/// Minimum
Min,
/// Maximum
Max,
}
impl HwMonAttributeItem {
fn to_attr_str(&self) -> &str {
match self {
Self::Input => "input",
Self::Min => "min",
Self::Max => "max",
}
}
}
impl HwMonAttribute {
/// `name` attribute
pub const fn name() -> Self {
Self {
inner: HwMonAttributeInner::Name
}
}
/// Custom attribute in standard format
pub const fn new(ty: HwMonAttributeType, number: u64, item: HwMonAttributeItem) -> Self {
Self {
inner: HwMonAttributeInner::Standard { ty, number, item }
}
}
/// `uevent` attribute
pub const fn uevent() -> Self {
Self {
inner: HwMonAttributeInner::Uevent
}
}
fn to_attr_str(&self) -> String {
match self.inner {
HwMonAttributeInner::Name => "name".to_string(),
HwMonAttributeInner::Standard { ty, number, item } => format!("{}{}_{}", ty.to_attr_str(), number, item.to_attr_str()),
HwMonAttributeInner::Uevent => "uevent".to_string(),
}
}
}
/// hwmon<number>/ directory
pub struct HwMonPath {
path: PathBuf
}
impl HwMonPath {
pub(crate) fn all(root: impl AsRef<Path>) -> IoResult<impl Iterator<Item=IoResult<Self>>> {
let hwmon_dir_path = root.as_ref().join(HWMON_DIR_PATH);
hwmon_dir_path.read_dir()
.map(
|iter| iter.filter_map(
|entry| entry.map(
|entry| if crate::os_str_util::starts_with(&entry.file_name(), "hwmon".as_ref()) {
Some(Self {
path: entry.path(),
})
} else {
None
}).transpose()))
}
/// Get a hwmon entry by index.
/// This does not check if it exists.
pub(crate) fn entry(root: &crate::SysPath, i: u64) -> Self {
Self {
path: root.as_ref().join(HWMON_DIR_PATH).join(format!("hwmon{}", i)),
}
}
/// Get a hwmon entry by name, if it exists
pub(crate) fn name(root: &crate::SysPath, name: &str) -> IoResult<Option<Self>> {
for entry in Self::all(root)? {
let entry = entry?;
if entry.attribute(HwMonAttribute::name())? == name {
return Ok(Some(entry))
}
}
Ok(None)
}
/// Get a hwmon attribute (file contents) by attribute filename.
/// It is recommended to use HwMon.attribute unless the attribute has a non-standard name
pub fn attribute_str(&self, name: &str) -> IoResult<String> {
std::fs::read_to_string(self.path.join(name))
}
/// Get a hwmon attribute (file contents)
pub fn attribute(&self, attr: HwMonAttribute) -> IoResult<String> {
self.attribute_str(&attr.to_attr_str())
}
/// Get the path to a hwmon attribute.
/// Use `HwMonPath.as_ref().join(attribute_str)` for non-standard attributes
pub fn path_to(&self, attr: HwMonAttribute) -> PathBuf {
self.path.join(&attr.to_attr_str())
}
}
impl AsRef<Path> for HwMonPath {
fn as_ref(&self) -> &Path {
self.path.as_path()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hwmon_all() -> std::io::Result<()> {
let sys = crate::SysPath::default();
let all_hwmon: Vec<_> = HwMonPath::all(sys)?.collect();
assert!(!all_hwmon.is_empty());
for hwmon in all_hwmon.into_iter() {
assert!(hwmon?.attribute(HwMonAttribute::name())? != "");
}
Ok(())
}
}

View file

@ -1,6 +1,16 @@
pub fn add(left: usize, right: usize) -> usize { #![warn(missing_docs)]
left + right //! Utility library for manipulating files in the Linux sysfs
} //!
pub(crate) const DEFAULT_ROOT: &'static str = "/";
mod hwmon;
pub use hwmon::{HwMonPath, HwMonAttribute, HwMonAttributeType, HwMonAttributeItem};
mod syspath;
pub use syspath::SysPath;
pub(crate) mod os_str_util;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -8,7 +18,7 @@ mod tests {
#[test] #[test]
fn it_works() { fn it_works() {
let result = add(2, 2); SysPath::default();
assert_eq!(result, 4); SysPath::path("/");
} }
} }

12
src/os_str_util.rs Normal file
View file

@ -0,0 +1,12 @@
use std::ffi::OsStr;
use std::os::unix::ffi::OsStrExt;
pub fn starts_with(src: &OsStr, contains: &OsStr) -> bool {
let src_bytes = src.as_bytes();
for (index, byte) in contains.as_bytes().iter().enumerate() {
if src_bytes[index] != *byte {
return false;
}
}
true
}

47
src/syspath.rs Normal file
View file

@ -0,0 +1,47 @@
use std::path::{Path, PathBuf};
use std::convert::AsRef;
/// sysfs root
pub struct SysPath {
root: PathBuf,
}
impl SysPath {
/// Initialize with a custom root.
/// Use SysPath::default() to use the default root `/`.
pub fn path(root: impl AsRef<Path>) -> Self {
Self {
root: root.as_ref().to_path_buf()
}
}
/// Find a hardware monitor entry by name
pub fn hwmon_by_name(&self, name: &str) -> std::io::Result<crate::HwMonPath> {
match crate::HwMonPath::name(self, name) {
Ok(None) => Err(std::io::Error::from_raw_os_error(std::io::ErrorKind::NotFound as _)),
Ok(Some(x)) => Ok(x),
Err(e) => Err(e)
}
}
/// Find a hardware monitor entry by index
pub fn hwmon_by_index(&self, index: u64) -> std::io::Result<crate::HwMonPath> {
let entry = crate::HwMonPath::entry(self, index);
entry.attribute(crate::HwMonAttribute::name())?;
Ok(entry)
}
}
impl std::default::Default for SysPath {
fn default() -> Self {
Self {
root: PathBuf::from(crate::DEFAULT_ROOT)
}
}
}
impl AsRef<Path> for SysPath {
fn as_ref(&self) -> &Path {
self.root.as_path()
}
}