#![allow(clippy::unnecessary_cast)]
use crate::extra;
use crate::shared;
use crate::traits::*;
use crate::winman;
use std::fs;
use std::path::{Path, PathBuf};
use sysctl::{Ctl, Sysctl};
impl From<sqlite::Error> for ReadoutError {
fn from(e: sqlite::Error) -> Self {
ReadoutError::Other(e.to_string())
}
}
pub struct FreeBSDBatteryReadout {
battery_state_ctl: Option<Ctl>,
battery_life_ctl: Option<Ctl>,
}
pub struct FreeBSDKernelReadout {
os_release_ctl: Option<Ctl>,
os_type_ctl: Option<Ctl>,
}
pub struct FreeBSDGeneralReadout {
hostname_ctl: Option<Ctl>,
model_ctl: Option<Ctl>,
}
pub struct FreeBSDMemoryReadout {
physmem_ctl: Option<Ctl>,
usermem_ctl: Option<Ctl>,
}
pub struct FreeBSDProductReadout;
pub struct FreeBSDPackageReadout;
pub struct FreeBSDNetworkReadout;
impl BatteryReadout for FreeBSDBatteryReadout {
fn new() -> Self {
FreeBSDBatteryReadout {
battery_state_ctl: Ctl::new("hw.acpi.battery.state").ok(),
battery_life_ctl: Ctl::new("hw.acpi.battery.life").ok(),
}
}
fn percentage(&self) -> Result<u8, ReadoutError> {
if let Some(ctl) = &self.battery_life_ctl {
if let Ok(val) = ctl.value_string() {
if let Ok(to_int) = val.parse::<u8>() {
return Ok(to_int);
}
}
}
Err(ReadoutError::MetricNotAvailable)
}
fn status(&self) -> Result<BatteryState, ReadoutError> {
if let Some(ctl) = &self.battery_state_ctl {
if let Ok(val) = ctl.value_string() {
if let Ok(to_int) = val.parse::<u8>() {
match to_int {
1 => return Ok(BatteryState::Discharging),
2 => return Ok(BatteryState::Charging),
_ => {
return Err(ReadoutError::Other(
"An unsupported battery state was reported.".to_string(),
))
}
};
}
}
}
Err(ReadoutError::MetricNotAvailable)
}
fn health(&self) -> Result<u64, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
}
impl KernelReadout for FreeBSDKernelReadout {
fn new() -> Self {
FreeBSDKernelReadout {
os_release_ctl: Ctl::new("kernel.osrelease").ok(),
os_type_ctl: Ctl::new("kernel.ostype").ok(),
}
}
fn os_release(&self) -> Result<String, ReadoutError> {
Ok(self
.os_release_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap())
}
fn os_type(&self) -> Result<String, ReadoutError> {
Ok(self
.os_type_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap())
}
fn pretty_kernel(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
}
impl GeneralReadout for FreeBSDGeneralReadout {
fn new() -> Self {
FreeBSDGeneralReadout {
hostname_ctl: Ctl::new("kern.hostname").ok(),
model_ctl: Ctl::new("hw.model").ok(),
}
}
fn resolution(&self) -> Result<String, ReadoutError> {
shared::resolution()
}
fn backlight(&self) -> Result<usize, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn machine(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn username(&self) -> Result<String, ReadoutError> {
shared::username()
}
fn hostname(&self) -> Result<String, ReadoutError> {
Ok(self
.hostname_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap())
}
fn distribution(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn desktop_environment(&self) -> Result<String, ReadoutError> {
shared::desktop_environment()
}
fn session(&self) -> Result<String, ReadoutError> {
shared::session()
}
fn window_manager(&self) -> Result<String, ReadoutError> {
winman::detect_xorg_window_manager()
}
fn terminal(&self) -> Result<String, ReadoutError> {
fn get_parent(pid: i32) -> i32 {
let process_path = PathBuf::from("/proc").join(pid.to_string()).join("status");
if let Ok(content) = fs::read_to_string(process_path) {
if let Some(val) = content.split_whitespace().nth(2) {
if let Ok(c) = val.parse::<i32>() {
return c;
}
}
return -1;
}
-1
}
fn terminal_name() -> String {
let mut terminal_pid = get_parent(unsafe { libc::getppid() });
let path = PathBuf::from("/proc")
.join(terminal_pid.to_string())
.join("status");
if let Ok(mut terminal_name) = fs::read_to_string(path) {
terminal_name = terminal_name.split_whitespace().next().unwrap().to_owned();
while extra::common_shells().contains(&terminal_name.as_str()) {
let ppid = get_parent(terminal_pid);
terminal_pid = ppid;
let path = PathBuf::from("/proc")
.join(terminal_pid.to_string())
.join("status");
if let Ok(status) = fs::read_to_string(path) {
if let Some(name) = status.split_whitespace().next() {
terminal_name = name.to_string();
}
}
}
return terminal_name;
}
String::new()
}
let terminal = terminal_name();
if terminal.is_empty() {
return Err(ReadoutError::Other(
"Could not to fetch terminal.".to_string(),
));
}
Ok(terminal)
}
fn shell(&self, shorthand: ShellFormat, kind: ShellKind) -> Result<String, ReadoutError> {
shared::shell(shorthand, kind)
}
fn cpu_model_name(&self) -> Result<String, ReadoutError> {
Ok(self
.model_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap())
}
fn cpu_cores(&self) -> Result<usize, ReadoutError> {
shared::cpu_cores()
}
fn cpu_physical_cores(&self) -> Result<usize, ReadoutError> {
shared::cpu_physical_cores()
}
fn cpu_usage(&self) -> Result<usize, ReadoutError> {
shared::cpu_usage()
}
fn uptime(&self) -> Result<usize, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn os_name(&self) -> Result<String, ReadoutError> {
let kernel_readout = FreeBSDKernelReadout::new();
let os_type = kernel_readout.os_type()?;
let os_release = kernel_readout.os_release()?;
if !(os_type.is_empty() || os_release.is_empty()) {
return Ok(format!("{} {}", os_type, os_release));
}
Err(ReadoutError::MetricNotAvailable)
}
fn disk_space(&self) -> Result<(u128, u128), ReadoutError> {
shared::disk_space(String::from("/"))
}
}
impl MemoryReadout for FreeBSDMemoryReadout {
fn new() -> Self {
FreeBSDMemoryReadout {
physmem_ctl: Ctl::new("hw.physmem").ok(),
usermem_ctl: Ctl::new("hw.usermem").ok(),
}
}
fn total(&self) -> Result<u64, ReadoutError> {
Ok(self
.physmem_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap()
.parse::<u64>()
.unwrap()
/ 1024)
}
fn free(&self) -> Result<u64, ReadoutError> {
Ok(self
.usermem_ctl
.as_ref()
.ok_or(ReadoutError::MetricNotAvailable)?
.value_string()
.unwrap()
.parse::<u64>()
.unwrap()
/ 1024)
}
fn buffers(&self) -> Result<u64, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn cached(&self) -> Result<u64, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn reclaimable(&self) -> Result<u64, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn used(&self) -> Result<u64, ReadoutError> {
let total = self.total().unwrap();
let free = self.free().unwrap();
Ok(total - free)
}
}
impl ProductReadout for FreeBSDProductReadout {
fn new() -> Self {
FreeBSDProductReadout
}
fn family(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn vendor(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
fn product(&self) -> Result<String, ReadoutError> {
Err(ReadoutError::MetricNotAvailable)
}
}
impl PackageReadout for FreeBSDPackageReadout {
fn new() -> Self {
FreeBSDPackageReadout
}
fn count_pkgs(&self) -> Vec<(PackageManager, usize)> {
let mut packages = Vec::new();
if let Some(c) = FreeBSDPackageReadout::count_pkg() {
packages.push((PackageManager::Pkg, c));
}
if let Some(c) = FreeBSDPackageReadout::count_cargo() {
packages.push((PackageManager::Cargo, c));
}
packages
}
}
impl FreeBSDPackageReadout {
fn count_pkg() -> Option<usize> {
let db = "/var/db/pkg/local.sqlite";
if !Path::new(db).exists() {
return None;
}
let connection = sqlite::open(db);
if let Ok(con) = connection {
let statement = con.prepare("SELECT COUNT(*) FROM packages");
if let Ok(mut s) = statement {
if s.next().is_ok() {
return match s.read::<Option<i64>>(0) {
Ok(Some(count)) => Some(count as usize),
_ => None,
};
}
}
}
None
}
fn count_cargo() -> Option<usize> {
shared::count_cargo()
}
}
impl NetworkReadout for FreeBSDNetworkReadout {
fn new() -> Self {
FreeBSDNetworkReadout
}
fn tx_bytes(&self, _: Option<&str>) -> Result<usize, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn tx_packets(&self, _: Option<&str>) -> Result<usize, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn rx_bytes(&self, _: Option<&str>) -> Result<usize, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn rx_packets(&self, _: Option<&str>) -> Result<usize, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
fn logical_address(&self, interface: Option<&str>) -> Result<String, ReadoutError> {
shared::logical_address(interface)
}
fn physical_address(&self, _: Option<&str>) -> Result<String, ReadoutError> {
Err(ReadoutError::NotImplemented)
}
}