955 lines
25 KiB
Rust
955 lines
25 KiB
Rust
use ipc::client::Client;
|
|
use rule::parser::{Str, When};
|
|
use rustc_hash::FxHashMap;
|
|
use std::{
|
|
ffi::{CStr, CString},
|
|
str::FromStr,
|
|
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),
|
|
}))
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_ref(udev: *mut Udev) -> *mut Udev {
|
|
unsafe {
|
|
(*udev).refcount.fetch_add(1, atomic::Ordering::SeqCst);
|
|
}
|
|
udev
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_unref(udev: *mut Udev) -> *mut Udev {
|
|
unsafe {
|
|
let oldval = (*udev).refcount.fetch_sub(1, atomic::Ordering::SeqCst);
|
|
if oldval == 1 {
|
|
drop(Box::from_raw(udev));
|
|
std::ptr::null_mut()
|
|
} else {
|
|
udev
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_get_userdata(udev: *const Udev) -> *mut u8 {
|
|
unsafe { (*udev).userdata }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_set_userdata(udev: *mut Udev, userdata: *mut u8) {
|
|
unsafe {
|
|
(*udev).userdata = userdata;
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevListEntry {
|
|
key: CString,
|
|
value: CString,
|
|
next: Option<Box<UdevListEntry>>,
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_list_entry_get_next(
|
|
entry: *const UdevListEntry,
|
|
) -> *const UdevListEntry {
|
|
unsafe {
|
|
(*entry)
|
|
.next
|
|
.as_ref()
|
|
.map(|x| &raw const **x)
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_list_entry_get_by_name(
|
|
mut entry: *const UdevListEntry,
|
|
name: *const libc::c_char,
|
|
) -> *const UdevListEntry {
|
|
unsafe {
|
|
let name = CStr::from_ptr(name);
|
|
while !entry.is_null() {
|
|
if (*entry).key == name {
|
|
return entry;
|
|
}
|
|
entry = udev_list_entry_get_next(entry);
|
|
}
|
|
std::ptr::null()
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_list_entry_get_name(
|
|
entry: *const UdevListEntry,
|
|
) -> *const libc::c_char {
|
|
unsafe { (*entry).key.as_ptr() }
|
|
}
|
|
|
|
#[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() }
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevDevice {
|
|
refcount: AtomicUsize,
|
|
udev: *mut Udev,
|
|
properties: UdevListEntry,
|
|
syspath: Option<CString>,
|
|
devlinks: UdevListEntry,
|
|
tags: UdevListEntry,
|
|
sysattr: UdevListEntry,
|
|
action: Option<CString>,
|
|
seqnum: libc::c_ulonglong,
|
|
sysattr_cache: FxHashMap<CString, CString>,
|
|
}
|
|
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 sysattr = Vec::new();
|
|
if let Some(syspath_str) = &syspath_str
|
|
&& let Ok(read_dir) = std::fs::read_dir(syspath_str)
|
|
{
|
|
for i in read_dir {
|
|
let Ok(i) = i else {
|
|
break;
|
|
};
|
|
sysattr.push(i.file_name().to_string_lossy().to_string());
|
|
}
|
|
}
|
|
let sysattr = vec_to_list(&sysattr);
|
|
Self {
|
|
refcount: AtomicUsize::new(1),
|
|
udev,
|
|
properties: *hashmap_to_list(&properties),
|
|
syspath,
|
|
devlinks: *devlinks,
|
|
tags: *tags,
|
|
sysattr: *sysattr,
|
|
action: None,
|
|
seqnum: 0,
|
|
sysattr_cache: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
impl Drop for UdevDevice {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
udev_unref(self.udev);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_new_from_syspath(
|
|
_udev: *mut Udev,
|
|
_syspath: *const libc::c_char,
|
|
) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_new_from_devnum(
|
|
_udev: *mut Udev,
|
|
_type: libc::c_char,
|
|
_devnum: libc::dev_t,
|
|
) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_new_from_subsystem_sysname(
|
|
_udev: *mut Udev,
|
|
_subsystem: *const libc::c_char,
|
|
_sysname: *const libc::c_char,
|
|
) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_new_from_device_id(
|
|
_udev: *mut Udev,
|
|
_id: *const libc::c_char,
|
|
) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_new_from_environment(_udev: *mut Udev) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_parent(_dev: *mut UdevDevice) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_parent_with_subsystem_devtype(
|
|
_dev: *mut UdevDevice,
|
|
_subsystem: *const libc::c_char,
|
|
_devtype: *const libc::c_char,
|
|
) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_ref(dev: *mut UdevDevice) -> *mut UdevDevice {
|
|
unsafe {
|
|
(*dev).refcount.fetch_add(1, atomic::Ordering::SeqCst);
|
|
}
|
|
dev
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_unref(dev: *mut UdevDevice) -> *mut UdevDevice {
|
|
unsafe {
|
|
let oldval = (*dev).refcount.fetch_sub(1, atomic::Ordering::SeqCst);
|
|
if oldval == 1 {
|
|
drop(Box::from_raw(dev));
|
|
std::ptr::null_mut()
|
|
} else {
|
|
dev
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_udev(dev: *const UdevDevice) -> *mut Udev {
|
|
unsafe { (*dev).udev }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_devpath(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe { udev_device_get_property_value(dev, c"DEVPATH".as_ptr()) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_subsystem(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe { udev_device_get_property_value(dev, c"SUBSYSTEM".as_ptr()) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_devtype(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe { udev_device_get_property_value(dev, c"DEVTYPE".as_ptr()) }
|
|
}
|
|
|
|
#[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(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_sysname(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe {
|
|
if dev.is_null() {
|
|
return std::ptr::null();
|
|
}
|
|
let Some(syspath) = (*dev).syspath.as_ref() else {
|
|
return std::ptr::null();
|
|
};
|
|
let split_pos = syspath.as_bytes().iter().rposition(|x| *x == b'/');
|
|
let offset = split_pos.map(|x| x + 1).unwrap_or_default();
|
|
syspath.as_ptr().add(offset)
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_sysnum(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe {
|
|
let mut sysname = udev_device_get_sysname(dev);
|
|
let mut found: *const libc::c_char = std::ptr::null();
|
|
if sysname.is_null() {
|
|
return std::ptr::null();
|
|
}
|
|
while *sysname != 0 {
|
|
if found.is_null() && (*sysname as char).is_ascii_digit() {
|
|
found = sysname;
|
|
}
|
|
if !found.is_null() && (*sysname as char).is_ascii_alphabetic() {
|
|
found = std::ptr::null();
|
|
}
|
|
sysname = sysname.add(1);
|
|
}
|
|
found
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_devnode(dev: *const UdevDevice) -> *const libc::c_char {
|
|
unsafe { udev_device_get_property_value(dev, c"DEVNODE".as_ptr()) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_is_initialized(_: *const UdevDevice) -> libc::c_int {
|
|
1
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_devlinks_list_entry(
|
|
dev: *const UdevDevice,
|
|
) -> *const UdevListEntry {
|
|
unsafe { &raw const (*dev).devlinks }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_properties_list_entry(
|
|
dev: *const UdevDevice,
|
|
) -> *const UdevListEntry {
|
|
unsafe { &raw const (*dev).properties }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_tags_list_entry(
|
|
dev: *const UdevDevice,
|
|
) -> *const UdevListEntry {
|
|
unsafe { &raw const (*dev).tags }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_current_tags_list_entry(
|
|
dev: *const UdevDevice,
|
|
) -> *const UdevListEntry {
|
|
unsafe { &raw const (*dev).tags }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_sysattr_list_entry(
|
|
dev: *const UdevDevice,
|
|
) -> *const UdevListEntry {
|
|
unsafe { &raw const (*dev).sysattr }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
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(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_driver(dev: *mut UdevDevice) -> *const libc::c_char {
|
|
unsafe { udev_device_get_sysattr_value(dev, c"driver".as_ptr()) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_devnum(dev: *const UdevDevice) -> libc::dev_t {
|
|
unsafe {
|
|
let devnode = udev_device_get_devnode(dev);
|
|
if devnode.is_null() {
|
|
return 0;
|
|
}
|
|
let mut statbuf = std::mem::zeroed();
|
|
let status = libc::lstat(devnode, &mut statbuf);
|
|
if status != 0 {
|
|
return 0;
|
|
}
|
|
statbuf.st_rdev
|
|
}
|
|
}
|
|
|
|
#[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(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_seqnum(dev: *const UdevDevice) -> libc::c_ulonglong {
|
|
unsafe { (*dev).seqnum }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_usec_since_initialized(
|
|
_: *const UdevDevice,
|
|
) -> libc::c_ulonglong {
|
|
0
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_get_sysattr_value(
|
|
dev: *mut UdevDevice,
|
|
sysattr: *const libc::c_char,
|
|
) -> *const libc::c_char {
|
|
unsafe {
|
|
let sysattr = CStr::from_ptr(sysattr);
|
|
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 {
|
|
return std::ptr::null();
|
|
};
|
|
path.push('/');
|
|
path.push_str(sysattr_str);
|
|
let Ok(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
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_set_sysattr_value(
|
|
dev: *mut UdevDevice,
|
|
sysattr: *const libc::c_char,
|
|
value: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
let dev = &mut *dev;
|
|
let sysattr = match CStr::from_ptr(sysattr).to_str() {
|
|
Ok(s) => s,
|
|
Err(_) => return -libc::EINVAL,
|
|
};
|
|
let value = match CStr::from_ptr(value).to_str() {
|
|
Ok(s) => s,
|
|
Err(_) => return -libc::EINVAL,
|
|
};
|
|
let syspath = match dev.syspath.as_ref() {
|
|
Some(p) => p,
|
|
None => return -libc::ENOENT,
|
|
};
|
|
let path = match 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
|
|
}
|
|
Err(e) => match e.raw_os_error() {
|
|
Some(code) => -code,
|
|
None => -libc::EIO,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_has_tag(
|
|
dev: *const UdevDevice,
|
|
tag: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
(!udev_list_entry_get_by_name(udev_device_get_tags_list_entry(dev), tag).is_null()) as _
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_device_has_current_tag(
|
|
dev: *const UdevDevice,
|
|
tag: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
(!udev_list_entry_get_by_name(udev_device_get_tags_list_entry(dev), tag).is_null()) as _
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevMonitor {
|
|
udev: *mut Udev,
|
|
refcount: AtomicUsize,
|
|
}
|
|
impl Drop for UdevMonitor {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
udev_unref(self.udev);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_ref(mon: *mut UdevMonitor) -> *mut UdevMonitor {
|
|
unsafe {
|
|
(*mon).refcount.fetch_add(1, atomic::Ordering::SeqCst);
|
|
}
|
|
mon
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_unref(mon: *mut UdevMonitor) -> *mut UdevMonitor {
|
|
unsafe {
|
|
let oldval = (*mon).refcount.fetch_sub(1, atomic::Ordering::SeqCst);
|
|
if oldval == 1 {
|
|
drop(Box::from_raw(mon));
|
|
std::ptr::null_mut()
|
|
} else {
|
|
mon
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_get_udev(mon: *const UdevMonitor) -> *mut Udev {
|
|
unsafe { (*mon).udev }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_new_from_netlink(
|
|
udev: *mut Udev,
|
|
name: *const libc::c_char,
|
|
) -> *mut UdevMonitor {
|
|
unsafe {
|
|
let name = CStr::from_ptr(name);
|
|
if name != c"udev" {
|
|
return std::ptr::null_mut();
|
|
}
|
|
Box::into_raw(Box::new(UdevMonitor {
|
|
udev,
|
|
refcount: AtomicUsize::new(1),
|
|
}))
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_enable_receiving(_: *const UdevMonitor) -> libc::c_int {
|
|
-libc::EPERM
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_set_receive_buffer_size(
|
|
_: *const UdevMonitor,
|
|
_: libc::c_int,
|
|
) -> libc::c_int {
|
|
0
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_get_fd(_: *const UdevMonitor) -> libc::c_int {
|
|
-1
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_receive_device(_: *const UdevMonitor) -> *mut UdevDevice {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[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,
|
|
) -> libc::c_int {
|
|
-libc::EPERM
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_filter_add_match_tag(
|
|
_mon: *mut UdevMonitor,
|
|
_tag: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
-libc::EPERM
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_filter_update(_mon: *mut UdevMonitor) -> libc::c_int {
|
|
-libc::EPERM
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_monitor_filter_remove(_mon: *mut UdevMonitor) -> libc::c_int {
|
|
-libc::EPERM
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevEnumerate {
|
|
udev: *mut Udev,
|
|
refcount: AtomicUsize,
|
|
filters: Vec<When>,
|
|
result: Option<UdevListEntry>,
|
|
}
|
|
impl Drop for UdevEnumerate {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
udev_unref(self.udev);
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_ref(p: *mut UdevEnumerate) -> *mut UdevEnumerate {
|
|
unsafe {
|
|
(*p).refcount.fetch_add(1, atomic::Ordering::SeqCst);
|
|
}
|
|
p
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_unref(p: *mut UdevEnumerate) -> *mut UdevEnumerate {
|
|
unsafe {
|
|
let oldval = (*p).refcount.fetch_sub(1, atomic::Ordering::SeqCst);
|
|
if oldval == 1 {
|
|
drop(Box::from_raw(p));
|
|
std::ptr::null_mut()
|
|
} else {
|
|
p
|
|
}
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_get_udev(p: *mut UdevEnumerate) -> *mut Udev {
|
|
unsafe { (*p).udev }
|
|
}
|
|
|
|
#[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(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_subsystem(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
subsystem: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe { udev_enumerate_match(udev_enumerate, "SUBSYSTEM", subsystem, false) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_nomatch_subsystem(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
subsystem: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe { udev_enumerate_match(udev_enumerate, "SUBSYSTEM", subsystem, true) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_sysattr(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
sysattr: *const libc::c_char,
|
|
value: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
let Ok(sysattr) = CStr::from_ptr(sysattr).to_str() else {
|
|
return -libc::EINVAL;
|
|
};
|
|
udev_enumerate_match(udev_enumerate, sysattr, value, false)
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_nomatch_sysattr(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
sysattr: *const libc::c_char,
|
|
value: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
let Ok(sysattr) = CStr::from_ptr(sysattr).to_str() else {
|
|
return -libc::EINVAL;
|
|
};
|
|
udev_enumerate_match(udev_enumerate, sysattr, value, true)
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_property(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
property: *const libc::c_char,
|
|
value: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
let Ok(property) = CStr::from_ptr(property).to_str() else {
|
|
return -libc::EINVAL;
|
|
};
|
|
udev_enumerate_match(udev_enumerate, property, value, false)
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
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(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_tag(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
tag: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe { udev_enumerate_match(udev_enumerate, "TAGS", tag, false) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_parent(
|
|
_: *mut UdevEnumerate,
|
|
_: *mut libc::c_void,
|
|
) -> libc::c_int {
|
|
-libc::EOPNOTSUPP
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_match_is_initialized(
|
|
_: *mut UdevEnumerate,
|
|
) -> libc::c_int {
|
|
0
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_add_syspath(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
syspath: *const libc::c_char,
|
|
) -> libc::c_int {
|
|
unsafe { udev_enumerate_match(udev_enumerate, "SYSPATH", syspath, false) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
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) {
|
|
Ok(x) => x,
|
|
Err(_) => return -libc::EPERM,
|
|
};
|
|
(*udev_enumerate).result = Some(*vec_to_list(&result));
|
|
0
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_scan_subsystems(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
) -> libc::c_int {
|
|
unsafe { udev_enumerate_scan_devices(udev_enumerate) }
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_enumerate_get_list_entry(
|
|
udev_enumerate: *mut UdevEnumerate,
|
|
) -> *mut UdevListEntry {
|
|
unsafe {
|
|
(*udev_enumerate)
|
|
.result
|
|
.as_mut()
|
|
.map(|x| &raw mut *x)
|
|
.unwrap_or_default()
|
|
}
|
|
}
|
|
|
|
unsafe fn udev_enumerate_match(
|
|
this: *mut UdevEnumerate,
|
|
key: &str,
|
|
data: *const libc::c_char,
|
|
not: bool,
|
|
) -> libc::c_int {
|
|
unsafe {
|
|
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).filters.push(when);
|
|
0
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevQueue;
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_ref(_p: *mut UdevQueue) -> *mut UdevQueue {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_unref(_p: *mut UdevQueue) -> *mut UdevQueue {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_get_udev(_udev_queue: *mut UdevQueue) -> *mut Udev {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_new(_udev: *mut Udev) -> *mut UdevQueue {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_get_udev_is_active(_udev_queue: *mut UdevQueue) -> libc::c_int {
|
|
-1
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_get_queue_is_empty(_udev_queue: *mut UdevQueue) -> libc::c_int {
|
|
-1
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_get_fd(_udev_queue: *mut UdevQueue) -> libc::c_int {
|
|
-1
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_queue_flush(_udev_queue: *mut UdevQueue) -> libc::c_int {
|
|
-1
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct UdevHwdb;
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_hwdb_new(_udev: *mut Udev) -> *mut UdevHwdb {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_hwdb_ref(_p: *mut UdevHwdb) -> *mut UdevHwdb {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_hwdb_unref(_p: *mut UdevHwdb) -> *mut UdevHwdb {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_hwdb_get_properties_list_entry(
|
|
_hwdb: *mut UdevHwdb,
|
|
_modalias: *const libc::c_char,
|
|
_flags: libc::c_uint,
|
|
) -> *mut UdevListEntry {
|
|
std::ptr::null_mut()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn udev_util_encode_string(
|
|
s: *const std::ffi::c_char,
|
|
str_enc: *mut std::ffi::c_char,
|
|
len: usize,
|
|
) -> std::ffi::c_int {
|
|
unsafe {
|
|
libc::memcpy(str_enc.cast(), s.cast(), len);
|
|
}
|
|
len as _
|
|
}
|
|
|
|
fn hashmap_to_list(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,
|
|
next: None,
|
|
});
|
|
*tail = Some(entry);
|
|
tail = &mut tail.as_mut().unwrap().next;
|
|
}
|
|
|
|
head.unwrap_or(Box::new(UdevListEntry {
|
|
key: CString::new("").unwrap(),
|
|
value: CString::new("").unwrap(),
|
|
next: None,
|
|
}))
|
|
}
|
|
|
|
fn vec_to_list(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(),
|
|
next: None,
|
|
});
|
|
*tail = Some(entry);
|
|
tail = &mut tail.as_mut().unwrap().next;
|
|
}
|
|
|
|
head.unwrap_or_else(|| {
|
|
Box::new(UdevListEntry {
|
|
key: CString::new("").unwrap(),
|
|
value: CString::new("").unwrap(),
|
|
next: None,
|
|
})
|
|
})
|
|
}
|