use crate::interface::state::OperState;
use crate::interface::types::InterfaceType;
use std::convert::TryFrom;
use std::fs;
use std::path::{Path, PathBuf};
fn read_trimmed(path: impl AsRef<Path>) -> Option<String> {
fs::read_to_string(path).ok().map(|s| s.trim().to_owned())
}
fn exists(path: impl AsRef<Path>) -> bool {
Path::new(path.as_ref()).exists()
}
fn is_wifi_interface(ifname: &str) -> bool {
let base = PathBuf::from("/sys/class/net").join(ifname);
if let Some(ue) = read_trimmed(base.join("uevent")) {
if ue.lines().any(|l| l.trim() == "DEVTYPE=wlan") {
return true;
}
}
exists(base.join("wireless")) || exists(base.join("phy80211"))
}
pub fn is_virtual_interface(ifname: &str) -> bool {
let dev_link = PathBuf::from("/sys/class/net").join(ifname).join("device");
if !dev_link.exists() {
return true;
}
match dev_link.canonicalize() {
Ok(real) => real.starts_with("/sys/devices/virtual"),
Err(_) => false,
}
}
pub fn get_interface_type(ifname: &str) -> InterfaceType {
if is_wifi_interface(ifname) {
return InterfaceType::Wireless80211;
}
let p = PathBuf::from("/sys/class/net").join(ifname).join("type");
let ty = match read_trimmed(&p).and_then(|s| s.parse::<u32>().ok()) {
Some(v) => v,
None => return InterfaceType::Unknown,
};
if ty == super::arp::ARPHRD_ETHER {
InterfaceType::Ethernet
} else {
InterfaceType::try_from(ty).unwrap_or(InterfaceType::Unknown)
}
}
pub fn get_interface_speed(ifname: &str) -> Option<u64> {
let p = PathBuf::from("/sys/class/net").join(ifname).join("speed");
let s = read_trimmed(p)?;
let mbps: i64 = s.parse().ok()?;
if mbps <= 0 {
return None;
}
Some((mbps as u64) * 1_000_000)
}
pub fn operstate(ifname: &str) -> OperState {
let p = PathBuf::from("/sys/class/net")
.join(ifname)
.join("operstate");
read_trimmed(p)
.and_then(|s| s.parse::<OperState>().ok())
.unwrap_or(OperState::Unknown)
}