@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "kobject-uevent"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
netlink-sys = { version = "0.9", features = ["tokio_socket"] }
|
||||
rustc-hash = "2"
|
||||
@@ -0,0 +1,87 @@
|
||||
use netlink_sys::{
|
||||
AsyncSocket, AsyncSocketExt, SocketAddr, TokioSocket, protocols::NETLINK_KOBJECT_UEVENT,
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
pub const MULTICAST_GROUP_KERNEL: u32 = 1;
|
||||
|
||||
pub struct KobjectUeventSocket(TokioSocket);
|
||||
impl KobjectUeventSocket {
|
||||
pub fn connect(group: u32) -> std::io::Result<Self> {
|
||||
let mut socket = TokioSocket::new(NETLINK_KOBJECT_UEVENT)?;
|
||||
let addr = SocketAddr::new(0, group);
|
||||
socket.socket_mut().bind(&addr)?;
|
||||
Ok(Self(socket))
|
||||
}
|
||||
|
||||
pub async fn recv(&self) -> std::io::Result<KobjectUevent> {
|
||||
let (data, sender) = self.0.recv_from_full().await?;
|
||||
if sender.port_number() != 0 {
|
||||
return Err(std::io::ErrorKind::PermissionDenied.into());
|
||||
}
|
||||
Ok(KobjectUevent::parse(data.as_slice()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct KobjectUevent(FxHashMap<String, String>);
|
||||
impl KobjectUevent {
|
||||
pub fn inner(&self) -> &FxHashMap<String, String> {
|
||||
&self.0
|
||||
}
|
||||
pub fn parse(s: &[u8]) -> Self {
|
||||
let mut map = FxHashMap::default();
|
||||
for kvp in s.split(|x| *x == b'\0') {
|
||||
let Some(sep) = kvp.iter().position(|x| *x == b'=') else {
|
||||
continue;
|
||||
};
|
||||
let (key, val) = kvp.split_at(sep);
|
||||
let val = &val[1..];
|
||||
map.insert(
|
||||
String::from_utf8_lossy_owned(key.into()),
|
||||
String::from_utf8_lossy_owned(val.into()),
|
||||
);
|
||||
}
|
||||
Self(map)
|
||||
}
|
||||
|
||||
pub fn action(&self) -> Option<&str> {
|
||||
self.0.get("ACTION").map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn devpath(&self) -> Option<&str> {
|
||||
self.0.get("DEVPATH").map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn subsystem(&self) -> Option<&str> {
|
||||
self.0.get("SUBSYSTEM").map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn synth_uuid(&self) -> Option<&str> {
|
||||
self.0.get("SYNTH_UUID").map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn major(&self) -> Option<u32> {
|
||||
let major = self.0.get("MAJOR")?;
|
||||
major.parse().ok()
|
||||
}
|
||||
|
||||
pub fn minor(&self) -> Option<u32> {
|
||||
let minor = self.0.get("MINOR")?;
|
||||
minor.parse().ok()
|
||||
}
|
||||
|
||||
pub fn devname(&self) -> Option<&str> {
|
||||
self.0.get("DEVNAME").map(String::as_str)
|
||||
}
|
||||
|
||||
pub fn devmode(&self) -> Option<u16> {
|
||||
let devmode = self.0.get("DEVMODE")?;
|
||||
let devmode = devmode.strip_prefix("0")?;
|
||||
u16::from_str_radix(devmode, 8).ok()
|
||||
}
|
||||
|
||||
pub fn seqnum(&self) -> Option<&str> {
|
||||
self.0.get("SEQNUM").map(String::as_str)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user