extern crate libc;
extern crate libsensors_sys as libsensors;
pub use libsensors::sensors_feature_type as FeatureType;
pub use libsensors::sensors_subfeature_type as SubfeatureType;
use std::ffi::CStr;
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::sync::{Once, ONCE_INIT};
static INIT: Once = ONCE_INIT;
#[derive(Copy, Clone, Debug)]
pub enum LibsensorsError {
Wildcards,
NoEntry,
AccessRead,
Kernel,
DivZero,
ChipName,
BusName,
Parse,
AccessWrite,
IO,
Recursion,
Unknown,
}
impl LibsensorsError {
fn from_i32(e: i32) -> LibsensorsError {
use self::LibsensorsError::*;
match e {
libsensors::SENSORS_ERR_WILDCARDS => Wildcards,
libsensors::SENSORS_ERR_NO_ENTRY => NoEntry,
libsensors::SENSORS_ERR_ACCESS_R => AccessRead,
libsensors::SENSORS_ERR_KERNEL => Kernel,
libsensors::SENSORS_ERR_DIV_ZERO => DivZero,
libsensors::SENSORS_ERR_CHIP_NAME => ChipName,
libsensors::SENSORS_ERR_BUS_NAME => BusName,
libsensors::SENSORS_ERR_PARSE => Parse,
libsensors::SENSORS_ERR_ACCESS_W => AccessWrite,
libsensors::SENSORS_ERR_IO => IO,
libsensors::SENSORS_ERR_RECURSION => Recursion,
_ => Unknown,
}
}
}
impl std::fmt::Display for LibsensorsError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use std::error::Error;
write!(f, "libsensors error: {}", self.description())
}
}
impl std::error::Error for LibsensorsError {
fn description(&self) -> &str {
use self::LibsensorsError::*;
match *self {
Unknown => "Unknown error",
Wildcards => "Wildcard found in chip name",
NoEntry => "No such subfeature known",
AccessRead => "Can't read",
Kernel => "Kernel interface error",
DivZero => "Divide by zero",
ChipName => "Can't parse chip name",
BusName => "Can't parse bus name",
Parse => "General parse error",
AccessWrite => "Can't write",
IO => "I/O error",
Recursion => "Evaluation recurses too deep",
}
}
fn cause(&self) -> Option<&std::error::Error> {
None
}
}
#[derive(Copy, Clone, Debug)]
pub struct Sensors {
marker: PhantomData<()>,
}
#[derive(Copy, Clone, Debug)]
pub struct BusId {
bus_type: i16,
nr: i16,
}
#[derive(Debug)]
pub struct Chip {
inner: *const libsensors::sensors_chip_name,
prefix: String,
bus: BusId,
addr: i32,
path: PathBuf,
}
pub struct ChipIterator {
chip_name: Option<libsensors::sensors_chip_name>,
index: i32,
}
#[derive(Debug)]
pub struct Feature {
inner: *const libsensors::sensors_feature,
chip_ptr: *const libsensors::sensors_chip_name,
name: String,
number: i32,
feature_type: FeatureType,
}
pub struct FeatureIterator {
chip_ptr: *const libsensors::sensors_chip_name,
index: i32,
}
#[derive(Debug)]
pub struct Subfeature {
inner: *const libsensors::sensors_subfeature,
chip_ptr: *const libsensors::sensors_chip_name,
name: String,
number: i32,
subfeature_type: SubfeatureType,
mapping: i32,
flags: u32,
}
pub struct SubfeatureIterator {
chip_ptr: *const libsensors::sensors_chip_name,
feature_ptr: *const libsensors::sensors_feature,
index: i32,
}
impl Sensors {
pub fn new() -> Self {
INIT.call_once(|| unsafe {
assert_eq!(libsensors::sensors_init(std::ptr::null_mut()), 0);
assert_eq!(libc::atexit(Self::cleanup), 0);
});
Sensors {
marker: PhantomData,
}
}
extern "C" fn cleanup() {
unsafe {
libsensors::sensors_cleanup();
}
}
pub fn detected_chips<S: AsRef<str>>(&self, name: S) -> Result<ChipIterator, LibsensorsError> {
let c_name = std::ffi::CString::new(name.as_ref()).unwrap();
let mut chip_name = libsensors::sensors_chip_name {
prefix: std::ptr::null_mut(),
bus: libsensors::sensors_bus_id {
type_: Default::default(),
nr: Default::default(),
},
addr: Default::default(),
path: std::ptr::null_mut(),
};
let res = unsafe { libsensors::sensors_parse_chip_name(c_name.as_ptr(), &mut chip_name) };
if res == 0 {
let iterator = ChipIterator {
chip_name: Some(chip_name),
index: 0,
};
Ok(iterator)
} else {
Err(LibsensorsError::from_i32(res))
}
}
}
impl BusId {
pub fn bus_type(&self) -> i16 {
self.bus_type
}
pub fn nr(&self) -> i16 {
self.nr
}
pub fn get_adapter_name(&self) -> Option<String> {
let bus_id = libsensors::sensors_bus_id {
type_: self.bus_type,
nr: self.nr,
};
let cstr_ptr = unsafe { libsensors::sensors_get_adapter_name(&bus_id) };
if !cstr_ptr.is_null() {
let cstr = unsafe { CStr::from_ptr(cstr_ptr) };
Some(cstr.to_string_lossy().into_owned())
} else {
None
}
}
}
impl Chip {
unsafe fn from_ptr(ptr: *const libsensors::sensors_chip_name) -> Chip {
let chip = *ptr;
let prefix_cstr = CStr::from_ptr(chip.prefix);
let path_cstr = CStr::from_ptr(chip.path);
Chip {
inner: ptr,
prefix: prefix_cstr.to_string_lossy().into_owned(),
bus: BusId {
bus_type: chip.bus.type_,
nr: chip.bus.nr,
},
addr: chip.addr,
path: PathBuf::from(path_cstr.to_string_lossy().into_owned()),
}
}
fn c_ptr(&self) -> *const libsensors::sensors_chip_name {
self.inner
}
pub fn prefix(&self) -> &str {
self.prefix.as_str()
}
pub fn address(&self) -> i32 {
self.addr
}
pub fn path(&self) -> &Path {
self.path.as_path()
}
pub fn bus(&self) -> &BusId {
&self.bus
}
pub fn get_name(&self) -> Result<String, LibsensorsError> {
let mut buffer: [std::os::raw::c_char; 128] = [0; 128];
let res = unsafe {
libsensors::sensors_snprintf_chip_name(&mut buffer[0], buffer.len(), self.c_ptr())
};
if res >= 0 {
let name_cstr = unsafe { CStr::from_ptr(&buffer[0]) };
Ok(name_cstr.to_string_lossy().into_owned())
} else {
Err(LibsensorsError::from_i32(res))
}
}
}
impl Feature {
unsafe fn from_ptr(
ptr: *const libsensors::sensors_feature,
chip: *const libsensors::sensors_chip_name,
) -> Feature {
let feature = *ptr;
let name_cstr = CStr::from_ptr(feature.name);
Feature {
inner: ptr,
chip_ptr: chip,
name: name_cstr.to_string_lossy().into_owned(),
number: feature.number,
feature_type: feature.type_,
}
}
fn c_ptr(&self) -> *const libsensors::sensors_feature {
self.inner
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn number(&self) -> i32 {
self.number
}
pub fn feature_type(&self) -> &FeatureType {
&self.feature_type
}
pub fn get_label(&self) -> Result<String, LibsensorsError> {
let label_ptr = unsafe { libsensors::sensors_get_label(self.chip_ptr, self.c_ptr()) };
if !label_ptr.is_null() {
let label = unsafe { CStr::from_ptr(label_ptr).to_string_lossy().into_owned() };
unsafe {
libc::free(label_ptr as *mut libc::c_void);
}
Ok(label)
} else {
Err(LibsensorsError::Unknown)
}
}
pub fn get_subfeature(&self, subfeature_type: SubfeatureType) -> Option<Subfeature> {
let ptr = unsafe {
libsensors::sensors_get_subfeature(self.chip_ptr, self.c_ptr(), subfeature_type)
};
if !ptr.is_null() {
unsafe { Some(Subfeature::from_ptr(ptr, self.chip_ptr)) }
} else {
None
}
}
}
impl Subfeature {
unsafe fn from_ptr(
ptr: *const libsensors::sensors_subfeature,
chip: *const libsensors::sensors_chip_name,
) -> Subfeature {
let subfeature = *ptr;
let name_cstr = CStr::from_ptr(subfeature.name);
Subfeature {
inner: ptr,
chip_ptr: chip,
name: name_cstr.to_string_lossy().into_owned(),
number: subfeature.number,
subfeature_type: subfeature.type_,
mapping: subfeature.mapping,
flags: subfeature.flags,
}
}
pub fn name(&self) -> &str {
self.name.as_str()
}
pub fn subfeature_type(&self) -> &SubfeatureType {
&self.subfeature_type
}
pub fn get_value(&self) -> Result<f64, LibsensorsError> {
let mut value: f64 = 0.0;
let res = unsafe { libsensors::sensors_get_value(self.chip_ptr, self.number, &mut value) };
if res >= 0 {
Ok(value)
} else {
Err(LibsensorsError::from_i32(res))
}
}
pub fn set_value(&self, value: f64) -> Result<(), LibsensorsError> {
let res = unsafe { libsensors::sensors_set_value(self.chip_ptr, self.number, value) };
if res >= 0 {
Ok(())
} else {
Err(LibsensorsError::from_i32(res))
}
}
}
impl IntoIterator for Sensors {
type Item = Chip;
type IntoIter = ChipIterator;
fn into_iter(self) -> Self::IntoIter {
ChipIterator {
chip_name: None,
index: 0,
}.into_iter()
}
}
impl Iterator for ChipIterator {
type Item = Chip;
fn next(&mut self) -> Option<Self::Item> {
let ptr = unsafe { libsensors::sensors_get_detected_chips(self.chip_name.as_ref().map_or(std::ptr::null(), |x| x), &mut self.index) };
if !ptr.is_null() {
unsafe { Some(Chip::from_ptr(ptr)) }
} else {
None
}
}
}
impl Drop for ChipIterator {
fn drop(&mut self) {
if let Some(mut chip_name) = self.chip_name {
unsafe {
libsensors::sensors_free_chip_name(&mut chip_name);
}
};
}
}
impl IntoIterator for Chip {
type Item = Feature;
type IntoIter = FeatureIterator;
fn into_iter(self) -> Self::IntoIter {
FeatureIterator {
index: 0,
chip_ptr: self.c_ptr(),
}.into_iter()
}
}
impl Iterator for FeatureIterator {
type Item = Feature;
fn next(&mut self) -> Option<Self::Item> {
let ptr = unsafe { libsensors::sensors_get_features(self.chip_ptr, &mut self.index) };
if !ptr.is_null() && !self.chip_ptr.is_null() {
unsafe { Some(Feature::from_ptr(ptr, self.chip_ptr)) }
} else {
None
}
}
}
impl IntoIterator for Feature {
type Item = Subfeature;
type IntoIter = SubfeatureIterator;
fn into_iter(self) -> Self::IntoIter {
SubfeatureIterator {
index: 0,
chip_ptr: self.chip_ptr,
feature_ptr: self.c_ptr(),
}.into_iter()
}
}
impl Iterator for SubfeatureIterator {
type Item = Subfeature;
fn next(&mut self) -> Option<Self::Item> {
let ptr = unsafe {
libsensors::sensors_get_all_subfeatures(
self.chip_ptr,
self.feature_ptr,
&mut self.index,
)
};
if !ptr.is_null() {
unsafe { Some(Subfeature::from_ptr(ptr, self.chip_ptr)) }
} else {
None
}
}
}