@@ -10,4 +10,6 @@ crate-type = ["cdylib"]
|
||||
ipc = { path = "../../libs/ipc" }
|
||||
libc = "0.2"
|
||||
rustc-hash = "2"
|
||||
db = { path = "../../libs/db" }
|
||||
fnmatch-regex = "0.3"
|
||||
rule = { path = "../../libs/rule" }
|
||||
|
||||
+228
-135
@@ -1,26 +1,28 @@
|
||||
mod util;
|
||||
|
||||
use crate::util::FfiStringPool;
|
||||
use db::Db;
|
||||
use ipc::client::Client;
|
||||
use rule::parser::{Str, When};
|
||||
use rule::{
|
||||
engine::Engine,
|
||||
parser::{Str, When},
|
||||
};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::{
|
||||
ffi::{CStr, CString},
|
||||
str::FromStr,
|
||||
ffi::CStr,
|
||||
os::fd::AsRawFd,
|
||||
sync::atomic::{self, AtomicUsize},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Udev {
|
||||
client: Client,
|
||||
userdata: *mut u8,
|
||||
refcount: AtomicUsize,
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_new() -> *mut Udev {
|
||||
let Ok(client) = Client::connect() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
Box::into_raw(Box::new(Udev {
|
||||
client,
|
||||
userdata: std::ptr::null_mut(),
|
||||
refcount: AtomicUsize::new(1),
|
||||
}))
|
||||
@@ -61,8 +63,8 @@ pub unsafe extern "C" fn udev_set_userdata(udev: *mut Udev, userdata: *mut u8) {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct UdevListEntry {
|
||||
key: CString,
|
||||
value: CString,
|
||||
key: *const libc::c_char,
|
||||
value: *const libc::c_char,
|
||||
next: Option<Box<UdevListEntry>>,
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ pub unsafe extern "C" fn udev_list_entry_get_by_name(
|
||||
unsafe {
|
||||
let name = CStr::from_ptr(name);
|
||||
while !entry.is_null() {
|
||||
if (*entry).key == name {
|
||||
if CStr::from_ptr((*entry).key) == name {
|
||||
return entry;
|
||||
}
|
||||
entry = udev_list_entry_get_next(entry);
|
||||
@@ -100,14 +102,14 @@ pub unsafe extern "C" fn udev_list_entry_get_by_name(
|
||||
pub unsafe extern "C" fn udev_list_entry_get_name(
|
||||
entry: *const UdevListEntry,
|
||||
) -> *const libc::c_char {
|
||||
unsafe { (*entry).key.as_ptr() }
|
||||
unsafe { (*entry).key }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_list_entry_get_value(
|
||||
entry: *const UdevListEntry,
|
||||
) -> *const libc::c_char {
|
||||
unsafe { (*entry).value.as_ptr() }
|
||||
unsafe { (*entry).value }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -115,40 +117,33 @@ pub struct UdevDevice {
|
||||
refcount: AtomicUsize,
|
||||
udev: *mut Udev,
|
||||
properties: UdevListEntry,
|
||||
syspath: Option<CString>,
|
||||
syspath: Option<*const libc::c_char>,
|
||||
devlinks: UdevListEntry,
|
||||
tags: UdevListEntry,
|
||||
sysattr: UdevListEntry,
|
||||
action: Option<CString>,
|
||||
seqnum: libc::c_ulonglong,
|
||||
sysattr_cache: FxHashMap<CString, CString>,
|
||||
strings: FfiStringPool,
|
||||
}
|
||||
impl UdevDevice {
|
||||
fn new(udev: *mut Udev, properties: FxHashMap<String, String>) -> Self {
|
||||
let syspath_str = properties.get("DEVPATH").map(|x| format!("/sys/{x}"));
|
||||
let syspath = syspath_str
|
||||
.as_deref()
|
||||
.map(|x| CString::from_str(x).unwrap_or_default());
|
||||
let devlinks = properties
|
||||
.get("SYMLINKS")
|
||||
.map(|x| x.as_str())
|
||||
.unwrap_or_default()
|
||||
.split('\0')
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
let devlinks = vec_to_list(&devlinks);
|
||||
let tags = properties
|
||||
.get("TAGS")
|
||||
.map(|x| x.as_str())
|
||||
.unwrap_or_default()
|
||||
.split('\0')
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.to_string())
|
||||
.collect();
|
||||
let tags = vec_to_list(&tags);
|
||||
let mut strings = FfiStringPool::new();
|
||||
let syspath = properties.get("DEVPATH").map(|x| format!("/sys/{x}"));
|
||||
let devlinks = util::parse_zero_separated_list(
|
||||
properties
|
||||
.get("SYMLINKS")
|
||||
.map(|x| x.as_str())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let devlinks = vec_to_list(&mut strings, &devlinks);
|
||||
let tags = util::parse_zero_separated_list(
|
||||
properties
|
||||
.get("TAGS")
|
||||
.map(|x| x.as_str())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let tags = vec_to_list(&mut strings, &tags);
|
||||
let mut sysattr = Vec::new();
|
||||
if let Some(syspath_str) = &syspath_str
|
||||
if let Some(syspath_str) = &syspath
|
||||
&& let Ok(read_dir) = std::fs::read_dir(syspath_str)
|
||||
{
|
||||
for i in read_dir {
|
||||
@@ -158,18 +153,18 @@ impl UdevDevice {
|
||||
sysattr.push(i.file_name().to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
let sysattr = vec_to_list(&sysattr);
|
||||
let sysattr = vec_to_list(&mut strings, &sysattr);
|
||||
let properties = *hashmap_to_list(&mut strings, &properties);
|
||||
Self {
|
||||
refcount: AtomicUsize::new(1),
|
||||
udev,
|
||||
properties: *hashmap_to_list(&properties),
|
||||
syspath,
|
||||
udev: unsafe { udev_ref(udev) },
|
||||
properties,
|
||||
syspath: syspath.map(|x| strings.insert_rust(x).as_ptr()),
|
||||
devlinks: *devlinks,
|
||||
tags: *tags,
|
||||
sysattr: *sysattr,
|
||||
action: None,
|
||||
seqnum: 0,
|
||||
sysattr_cache: Default::default(),
|
||||
strings,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -183,19 +178,58 @@ impl Drop for UdevDevice {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_device_new_from_syspath(
|
||||
_udev: *mut Udev,
|
||||
_syspath: *const libc::c_char,
|
||||
udev: *mut Udev,
|
||||
syspath: *const libc::c_char,
|
||||
) -> *mut UdevDevice {
|
||||
std::ptr::null_mut()
|
||||
unsafe {
|
||||
let Ok(syspath) = CStr::from_ptr(syspath).to_str() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
let Some(devpath) = syspath.strip_prefix("/sys") else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
udev_device_new_from_lxdeviced_name(udev, devpath.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn udev_device_new_from_lxdeviced_name(udev: *mut Udev, name: String) -> *mut UdevDevice {
|
||||
let Ok(mut client) = Client::connect() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
let Ok(properties) = client.get_device(name) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
Box::into_raw(Box::new(UdevDevice::new(udev, properties)))
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_device_new_from_devnum(
|
||||
_udev: *mut Udev,
|
||||
_type: libc::c_char,
|
||||
_devnum: libc::dev_t,
|
||||
udev: *mut Udev,
|
||||
ty: libc::c_char,
|
||||
devnum: libc::dev_t,
|
||||
) -> *mut UdevDevice {
|
||||
std::ptr::null_mut()
|
||||
let block = When::Match(Str::Direct("SUBSYSTEM".into()), Str::Direct("block".into()));
|
||||
let ty = match ty {
|
||||
b'b' => block,
|
||||
b'c' => When::Not(Box::new(block)),
|
||||
_ => return std::ptr::null_mut(),
|
||||
};
|
||||
let major = libc::major(devnum);
|
||||
let minor = libc::minor(devnum);
|
||||
let major = When::Match(Str::Direct("MAJOR".into()), Str::Direct(major.to_string()));
|
||||
let minor = When::Match(Str::Direct("MINOR".into()), Str::Direct(minor.to_string()));
|
||||
let devnum = When::All(vec![major, minor]);
|
||||
let when = When::All(vec![ty, devnum]);
|
||||
let Ok(mut client) = Client::connect() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
let Ok(result) = client.list_devices(when) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
let Some(devname) = result.first() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
udev_device_new_from_lxdeviced_name(udev, devname.into())
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -277,13 +311,7 @@ pub unsafe extern "C" fn udev_device_get_devtype(dev: *const UdevDevice) -> *con
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_device_get_syspath(dev: *const UdevDevice) -> *const libc::c_char {
|
||||
unsafe {
|
||||
(*dev)
|
||||
.syspath
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
unsafe { (*dev).syspath.as_ref().copied().unwrap_or_default() }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -292,12 +320,15 @@ pub unsafe extern "C" fn udev_device_get_sysname(dev: *const UdevDevice) -> *con
|
||||
if dev.is_null() {
|
||||
return std::ptr::null();
|
||||
}
|
||||
let Some(syspath) = (*dev).syspath.as_ref() else {
|
||||
let Some(syspath) = (*dev).syspath else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
let split_pos = syspath.as_bytes().iter().rposition(|x| *x == b'/');
|
||||
let split_pos = CStr::from_ptr(syspath)
|
||||
.to_bytes()
|
||||
.iter()
|
||||
.rposition(|x| *x == b'/');
|
||||
let offset = split_pos.map(|x| x + 1).unwrap_or_default();
|
||||
syspath.as_ptr().add(offset)
|
||||
syspath.add(offset)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +403,13 @@ pub unsafe extern "C" fn udev_device_get_property_value(
|
||||
dev: *const UdevDevice,
|
||||
key: *const libc::c_char,
|
||||
) -> *const libc::c_char {
|
||||
unsafe { udev_list_entry_get_value(udev_list_entry_get_by_name(&(*dev).properties, key)) }
|
||||
unsafe {
|
||||
let entry = udev_list_entry_get_by_name(&(*dev).properties, key);
|
||||
if entry.is_null() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
udev_list_entry_get_value(entry)
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -398,13 +435,7 @@ pub unsafe extern "C" fn udev_device_get_devnum(dev: *const UdevDevice) -> libc:
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_device_get_action(dev: *const UdevDevice) -> *const libc::c_char {
|
||||
unsafe {
|
||||
(*dev)
|
||||
.action
|
||||
.as_ref()
|
||||
.map(|x| x.as_ptr())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
unsafe { udev_device_get_property_value(dev, c"ACTION".as_ptr()) }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -429,26 +460,21 @@ pub unsafe extern "C" fn udev_device_get_sysattr_value(
|
||||
let Ok(sysattr_str) = sysattr.to_str() else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
if let Some(val) = (*dev).sysattr_cache.get(sysattr) {
|
||||
return val.as_ptr();
|
||||
}
|
||||
let Some(syspath) = (*dev).syspath.as_ref() else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
let Ok(mut path) = String::from_utf8(syspath.as_bytes().to_vec()) else {
|
||||
let Ok(mut path) = String::from_utf8(CStr::from_ptr(*syspath).to_bytes().to_vec()) else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
path.push('/');
|
||||
path.push_str(sysattr_str);
|
||||
let Ok(data) = std::fs::read_to_string(path) else {
|
||||
let Ok(mut data) = std::fs::read_to_string(path) else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
let Ok(data) = CString::from_str(&data) else {
|
||||
return std::ptr::null();
|
||||
};
|
||||
let ptr = data.as_ptr();
|
||||
(*dev).sysattr_cache.insert(CString::from(sysattr), data);
|
||||
ptr
|
||||
if data.ends_with("\n") {
|
||||
data.pop();
|
||||
}
|
||||
(*dev).strings.insert_rust(data).as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,21 +498,12 @@ pub unsafe extern "C" fn udev_device_set_sysattr_value(
|
||||
Some(p) => p,
|
||||
None => return -libc::ENOENT,
|
||||
};
|
||||
let path = match syspath.to_str() {
|
||||
let path = match CStr::from_ptr(*syspath).to_str() {
|
||||
Ok(p) => format!("{}/{}", p, sysattr),
|
||||
Err(_) => return -libc::ENOENT,
|
||||
};
|
||||
match std::fs::write(&path, value) {
|
||||
Ok(_) => {
|
||||
if let Ok(cstr) = CString::new(value) {
|
||||
let key = match CString::new(sysattr) {
|
||||
Ok(k) => k,
|
||||
Err(_) => return 0,
|
||||
};
|
||||
dev.sysattr_cache.insert(key, cstr);
|
||||
}
|
||||
0
|
||||
}
|
||||
Ok(_) => 0,
|
||||
Err(e) => match e.raw_os_error() {
|
||||
Some(code) => -code,
|
||||
None => -libc::EIO,
|
||||
@@ -519,6 +536,8 @@ pub unsafe extern "C" fn udev_device_has_current_tag(
|
||||
pub struct UdevMonitor {
|
||||
udev: *mut Udev,
|
||||
refcount: AtomicUsize,
|
||||
client: Client,
|
||||
conditions: Vec<When>,
|
||||
}
|
||||
impl Drop for UdevMonitor {
|
||||
fn drop(&mut self) {
|
||||
@@ -560,20 +579,30 @@ pub unsafe extern "C" fn udev_monitor_new_from_netlink(
|
||||
name: *const libc::c_char,
|
||||
) -> *mut UdevMonitor {
|
||||
unsafe {
|
||||
let name = CStr::from_ptr(name);
|
||||
if name != c"udev" {
|
||||
if CStr::from_ptr(name) != c"udev" {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
let Ok(client) = Client::connect() else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
Box::into_raw(Box::new(UdevMonitor {
|
||||
udev,
|
||||
udev: udev_ref(udev),
|
||||
refcount: AtomicUsize::new(1),
|
||||
client,
|
||||
conditions: Vec::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_enable_receiving(_: *const UdevMonitor) -> libc::c_int {
|
||||
-libc::EPERM
|
||||
pub unsafe extern "C" fn udev_monitor_enable_receiving(monitor: *mut UdevMonitor) -> libc::c_int {
|
||||
unsafe {
|
||||
let monitor = &mut *monitor;
|
||||
match monitor.client.send(&ipc::repr::Request::WaitForEvent) {
|
||||
Ok(()) => 0,
|
||||
Err(err) => -err.raw_os_error().unwrap_or(libc::EPERM),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -585,40 +614,94 @@ pub unsafe extern "C" fn udev_monitor_set_receive_buffer_size(
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_get_fd(_: *const UdevMonitor) -> libc::c_int {
|
||||
-1
|
||||
pub unsafe extern "C" fn udev_monitor_get_fd(monitor: *const UdevMonitor) -> libc::c_int {
|
||||
unsafe { (*monitor).client.inner().as_raw_fd() }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_receive_device(_: *const UdevMonitor) -> *mut UdevDevice {
|
||||
std::ptr::null_mut()
|
||||
pub unsafe extern "C" fn udev_monitor_receive_device(monitor: *mut UdevMonitor) -> *mut UdevDevice {
|
||||
unsafe {
|
||||
let monitor = &mut *monitor;
|
||||
let db = Db::open_in_memory();
|
||||
loop {
|
||||
let result = monitor.client.recv::<String>();
|
||||
udev_monitor_enable_receiving(monitor);
|
||||
let Ok(Ok(result)) = result else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
let Ok(device) = monitor.client.get_device(result) else {
|
||||
return std::ptr::null_mut();
|
||||
};
|
||||
|
||||
let section = db.section("default");
|
||||
section.restore(device.clone());
|
||||
let engine = Engine::with_properties(section);
|
||||
if !engine
|
||||
.exec_condition(&When::All(monitor.conditions.clone()))
|
||||
.unwrap_or_default()
|
||||
{
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
|
||||
return Box::into_raw(Box::new(UdevDevice::new(monitor.udev, device)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_filter_add_match_subsystem_devtype(
|
||||
_mon: *mut UdevMonitor,
|
||||
_subsystem: *const libc::c_char,
|
||||
_devtype: *const libc::c_char,
|
||||
mon: *mut UdevMonitor,
|
||||
subsystem: *const libc::c_char,
|
||||
devtype: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
-libc::EPERM
|
||||
unsafe {
|
||||
udev_monitor_match(mon, "SUBSYSTEM", subsystem, false);
|
||||
udev_monitor_match(mon, "DEVTYPE", devtype, false);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_filter_add_match_tag(
|
||||
_mon: *mut UdevMonitor,
|
||||
_tag: *const libc::c_char,
|
||||
mon: *mut UdevMonitor,
|
||||
tag: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
-libc::EPERM
|
||||
unsafe { udev_monitor_match(mon, "TAGS", tag, false) }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_filter_update(_mon: *mut UdevMonitor) -> libc::c_int {
|
||||
-libc::EPERM
|
||||
0
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_monitor_filter_remove(_mon: *mut UdevMonitor) -> libc::c_int {
|
||||
-libc::EPERM
|
||||
pub unsafe extern "C" fn udev_monitor_filter_remove(mon: *mut UdevMonitor) -> libc::c_int {
|
||||
unsafe {
|
||||
(*mon).conditions.clear();
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn udev_monitor_match(
|
||||
this: *mut UdevMonitor,
|
||||
key: &str,
|
||||
data: *const libc::c_char,
|
||||
not: bool,
|
||||
) -> libc::c_int {
|
||||
unsafe {
|
||||
if data.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let Ok(data) = CStr::from_ptr(data).to_str() else {
|
||||
return -libc::EINVAL;
|
||||
};
|
||||
let mut when = When::Match(Str::Direct(key.into()), Str::Direct(data.into()));
|
||||
if not {
|
||||
when = When::Not(Box::new(when));
|
||||
}
|
||||
(*this).conditions.push(when);
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -627,6 +710,7 @@ pub struct UdevEnumerate {
|
||||
refcount: AtomicUsize,
|
||||
filters: Vec<When>,
|
||||
result: Option<UdevListEntry>,
|
||||
strings: FfiStringPool,
|
||||
}
|
||||
impl Drop for UdevEnumerate {
|
||||
fn drop(&mut self) {
|
||||
@@ -664,12 +748,15 @@ pub unsafe extern "C" fn udev_enumerate_get_udev(p: *mut UdevEnumerate) -> *mut
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn udev_enumerate_new(udev: *mut Udev) -> *mut UdevEnumerate {
|
||||
Box::into_raw(Box::new(UdevEnumerate {
|
||||
udev,
|
||||
refcount: AtomicUsize::new(1),
|
||||
filters: Vec::with_capacity(16),
|
||||
result: None,
|
||||
}))
|
||||
unsafe {
|
||||
Box::into_raw(Box::new(UdevEnumerate {
|
||||
udev: udev_ref(udev),
|
||||
refcount: AtomicUsize::new(1),
|
||||
filters: Vec::with_capacity(16),
|
||||
result: None,
|
||||
strings: FfiStringPool::new(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -735,7 +822,7 @@ pub unsafe extern "C" fn udev_enumerate_add_match_sysname(
|
||||
udev_enumerate: *mut UdevEnumerate,
|
||||
sysname: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
unsafe { udev_enumerate_match(udev_enumerate, "SYSNAME", sysname, false) }
|
||||
unsafe { udev_enumerate_match(udev_enumerate, "DEVNAME", sysname, false) }
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
@@ -774,13 +861,18 @@ pub unsafe extern "C" fn udev_enumerate_scan_devices(
|
||||
udev_enumerate: *mut UdevEnumerate,
|
||||
) -> libc::c_int {
|
||||
unsafe {
|
||||
let udev = (*udev_enumerate).udev;
|
||||
let when = When::All((*udev_enumerate).filters.clone());
|
||||
let result = match (*udev).client.list_devices(when) {
|
||||
let Ok(mut client) = Client::connect() else {
|
||||
return -libc::EPERM;
|
||||
};
|
||||
let mut result = match client.list_devices(when) {
|
||||
Ok(x) => x,
|
||||
Err(_) => return -libc::EPERM,
|
||||
};
|
||||
(*udev_enumerate).result = Some(*vec_to_list(&result));
|
||||
for i in &mut result {
|
||||
i.insert_str(0, "/sys");
|
||||
}
|
||||
(*udev_enumerate).result = Some(*vec_to_list(&mut (*udev_enumerate).strings, &result));
|
||||
0
|
||||
}
|
||||
}
|
||||
@@ -815,7 +907,8 @@ unsafe fn udev_enumerate_match(
|
||||
let Ok(data) = CStr::from_ptr(data).to_str() else {
|
||||
return -libc::EINVAL;
|
||||
};
|
||||
let mut when = When::Match(Str::Direct(key.into()), Str::Direct(data.into()));
|
||||
let regex = fnmatch_regex::glob_to_regex_pattern(data).unwrap_or_default();
|
||||
let mut when = When::PartMatch(Str::Direct(key.into()), Str::Direct((®ex[1..]).into()));
|
||||
if not {
|
||||
when = When::Not(Box::new(when));
|
||||
}
|
||||
@@ -906,16 +999,17 @@ pub unsafe extern "C" fn udev_util_encode_string(
|
||||
len as _
|
||||
}
|
||||
|
||||
fn hashmap_to_list(hashmap: &FxHashMap<String, String>) -> Box<UdevListEntry> {
|
||||
fn hashmap_to_list(
|
||||
strings: &mut FfiStringPool,
|
||||
hashmap: &FxHashMap<String, String>,
|
||||
) -> Box<UdevListEntry> {
|
||||
let mut head = None;
|
||||
let mut tail = &mut head;
|
||||
|
||||
for (key, value) in hashmap {
|
||||
let key_cstr = CString::new(key.as_str()).unwrap();
|
||||
let value_cstr = CString::new(value.as_str()).unwrap();
|
||||
let entry = Box::new(UdevListEntry {
|
||||
key: key_cstr,
|
||||
value: value_cstr,
|
||||
key: strings.insert_rust(key.clone()).as_ptr(),
|
||||
value: strings.insert_rust(value.clone()).as_ptr(),
|
||||
next: None,
|
||||
});
|
||||
*tail = Some(entry);
|
||||
@@ -923,21 +1017,20 @@ fn hashmap_to_list(hashmap: &FxHashMap<String, String>) -> Box<UdevListEntry> {
|
||||
}
|
||||
|
||||
head.unwrap_or(Box::new(UdevListEntry {
|
||||
key: CString::new("").unwrap(),
|
||||
value: CString::new("").unwrap(),
|
||||
key: std::ptr::null(),
|
||||
value: std::ptr::null(),
|
||||
next: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn vec_to_list(vec: &Vec<String>) -> Box<UdevListEntry> {
|
||||
fn vec_to_list(strings: &mut FfiStringPool, vec: &Vec<String>) -> Box<UdevListEntry> {
|
||||
let mut head = None;
|
||||
let mut tail = &mut head;
|
||||
|
||||
for s in vec {
|
||||
let cstr = CString::new(s.as_str()).unwrap();
|
||||
let entry = Box::new(UdevListEntry {
|
||||
key: cstr,
|
||||
value: CString::new("").unwrap(),
|
||||
key: strings.insert_rust(s.clone()).as_ptr(),
|
||||
value: strings.insert_rust("".into()).as_ptr(),
|
||||
next: None,
|
||||
});
|
||||
*tail = Some(entry);
|
||||
@@ -946,8 +1039,8 @@ fn vec_to_list(vec: &Vec<String>) -> Box<UdevListEntry> {
|
||||
|
||||
head.unwrap_or_else(|| {
|
||||
Box::new(UdevListEntry {
|
||||
key: CString::new("").unwrap(),
|
||||
value: CString::new("").unwrap(),
|
||||
key: std::ptr::null(),
|
||||
value: std::ptr::null(),
|
||||
next: None,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::ffi::{CStr, CString};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FfiStringPool {
|
||||
strings: FxHashMap<String, CString>,
|
||||
}
|
||||
impl FfiStringPool {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
strings: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_rust(&mut self, s: String) -> &CStr {
|
||||
let s = s.replace("\0", "");
|
||||
let entry = self.strings.entry(s);
|
||||
let value = entry.or_insert_with_key(|key| CString::new(key.clone()).unwrap());
|
||||
unsafe { &*(value.as_c_str() as *const CStr) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_zero_separated_list(s: &str) -> Vec<String> {
|
||||
s.split('\0')
|
||||
.filter(|x| !x.is_empty())
|
||||
.map(|x| x.to_string())
|
||||
.collect()
|
||||
}
|
||||
Reference in New Issue
Block a user