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>, } #[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, devlinks: UdevListEntry, tags: UdevListEntry, sysattr: UdevListEntry, action: Option, seqnum: libc::c_ulonglong, sysattr_cache: FxHashMap, } impl UdevDevice { fn new(udev: *mut Udev, properties: FxHashMap) -> 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, result: Option, } 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) -> Box { 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) -> Box { 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, }) }) }