use crate::{Error, Result};
pub(crate) fn sysctlbyname_int<T: TryFrom<u64>>(name: &str) -> Result<T> {
use std::ffi::CString;
let c_name = CString::new(name)
.map_err(|e| Error::Detection(format!("Invalid sysctl name {}: {}", name, e)))?;
let mut raw: u64 = 0;
let mut size = std::mem::size_of::<u64>();
let ret = unsafe {
libc::sysctlbyname(
c_name.as_ptr(),
&mut raw as *mut _ as *mut libc::c_void,
&mut size,
std::ptr::null_mut(),
0,
)
};
if ret == -1 {
let os_err = std::io::Error::last_os_error();
if os_err.raw_os_error() == Some(libc::ENOENT) {
return Err(Error::Detection(format!("Sysctl key {} not found", name)));
}
return Err(Error::SystemCall(format!(
"sysctlbyname for {} failed: {}",
name, os_err
)));
}
let value: u64 = match size {
4 => raw & 0xFFFF_FFFF,
8 => raw,
n => {
return Err(Error::Detection(format!(
"sysctlbyname for {} returned unexpected size: {} (expected 4 or 8)",
name, n
)));
}
};
T::try_from(value).map_err(|_| {
Error::Detection(format!(
"sysctl {} value {} does not fit the requested integer type",
name, value
))
})
}
pub(crate) fn sysctlbyname_string(name: &str) -> Result<String> {
use std::ffi::CString;
let c_name = CString::new(name)
.map_err(|e| Error::Detection(format!("Invalid sysctl name {}: {}", name, e)))?;
let mut size: libc::size_t = 0;
let ret = unsafe {
libc::sysctlbyname(
c_name.as_ptr(),
std::ptr::null_mut(),
&mut size,
std::ptr::null_mut(),
0,
)
};
if ret == -1 {
let os_err = std::io::Error::last_os_error();
if os_err.raw_os_error() == Some(libc::ENOENT) {
return Err(Error::Detection(format!("Sysctl key {} not found", name)));
}
return Err(Error::SystemCall(format!(
"sysctlbyname for {} (size query) failed: {}",
name, os_err
)));
}
if size == 0 {
return Ok(String::new());
}
let mut buf = vec![0u8; size as usize];
let ret = unsafe {
libc::sysctlbyname(
c_name.as_ptr(),
buf.as_mut_ptr() as *mut libc::c_void,
&mut size,
std::ptr::null_mut(),
0,
)
};
if ret == -1 {
return Err(Error::SystemCall(format!(
"sysctlbyname for {} (data query) failed: {}",
name,
std::io::Error::last_os_error()
)));
}
while !buf.is_empty() && buf[buf.len() - 1] == 0 {
buf.pop();
}
String::from_utf8(buf)
.map_err(|e| Error::Detection(format!("UTF-8 conversion error for {}: {}", name, e)))
}