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 {
|
#![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
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