Add root syspath and hwmon functionality
This commit is contained in:
parent
2e1d24250f
commit
1391e2fb2c
4 changed files with 253 additions and 5 deletions
179
src/hwmon.rs
Normal file
179
src/hwmon.rs
Normal 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(())
|
||||
}
|
||||
}
|
20
src/lib.rs
20
src/lib.rs
|
@ -1,6 +1,16 @@
|
|||
pub fn add(left: usize, right: usize) -> usize {
|
||||
left + right
|
||||
}
|
||||
#![warn(missing_docs)]
|
||||
//! 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)]
|
||||
mod tests {
|
||||
|
@ -8,7 +18,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
let result = add(2, 2);
|
||||
assert_eq!(result, 4);
|
||||
SysPath::default();
|
||||
SysPath::path("/");
|
||||
}
|
||||
}
|
||||
|
|
12
src/os_str_util.rs
Normal file
12
src/os_str_util.rs
Normal 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
47
src/syspath.rs
Normal 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()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue