diff options
Diffstat (limited to 'dom/webauthn/libudev-sys')
-rw-r--r-- | dom/webauthn/libudev-sys/Cargo.toml | 38 | ||||
-rw-r--r-- | dom/webauthn/libudev-sys/src/lib.rs | 182 |
2 files changed, 220 insertions, 0 deletions
diff --git a/dom/webauthn/libudev-sys/Cargo.toml b/dom/webauthn/libudev-sys/Cargo.toml new file mode 100644 index 0000000000..b438a56927 --- /dev/null +++ b/dom/webauthn/libudev-sys/Cargo.toml @@ -0,0 +1,38 @@ +# This is a fork of libudev-sys that dynamically loads its symbols with +# dlopen when they are first used. This continues a precedent established +# by Firefox's gamepad APIs to minimize the footprint of features when they +# aren't being used. Specifically, this avoids the cost of dynamically linking +# in libudev at process startup. +# +# "-sys" crates are a convention in the rust ecosystem for "a simple header +# for a C library that Rust code can use to build a richer and safer API on +# top of". In this case, libudev-sys is used by the [libudev crate]. +# +# As of this writing, this hack is being used by the [authenticator-rs] crate, +# which uses the libudev crate. +# +# The libudev crate assumes libudev is being dynamically linked in, and +# checks if its symbols are null before intializing anything else, so that +# you can use it to detect if libudev is installed and gracefully +# disable gamepads or whatever else if it's not. +# +# If we're missing any symbols the libudev crate needs, then rust will give +# us a compilation error. It's not a problem if we export additional symbols. +# +# So while this is a bit of a weird hack, it works pretty robustly, and this +# crate is basically just a header for libudev so it's not a particularly +# significant maintenance burden. +# +# authenticator-rs: https://github.com/mozilla/authenticator-rs +# libudev crate: https://crates.io/crates/libudev + +[package] +name = "libudev-sys" +version = "0.1.3" +authors = ["Tim Taubert <ttaubert@mozilla.com>"] +description = "FFI bindings to libudev" +license = "MPL-2.0" + +[dependencies] +lazy_static = "1.0" +libc = "0.2" diff --git a/dom/webauthn/libudev-sys/src/lib.rs b/dom/webauthn/libudev-sys/src/lib.rs new file mode 100644 index 0000000000..a08234a4c6 --- /dev/null +++ b/dom/webauthn/libudev-sys/src/lib.rs @@ -0,0 +1,182 @@ +/* -*- Mode: rust; rust-indent-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] + +#[macro_use] +extern crate lazy_static; +extern crate libc; + +use libc::{c_void,c_int,c_char,c_ulonglong,dev_t}; +use libc::{RTLD_GLOBAL,RTLD_LAZY,RTLD_NOLOAD}; +use libc::{dlopen,dlclose,dlsym}; +use std::ffi::CString; +use std::{marker,mem,ops,ptr}; + +#[repr(C)] +pub struct udev { + __private: c_void +} + +#[repr(C)] +pub struct udev_list_entry { + __private: c_void +} + +#[repr(C)] +pub struct udev_device { + __private: c_void +} + +#[repr(C)] +pub struct udev_monitor { + __private: c_void +} + +#[repr(C)] +pub struct udev_enumerate { + __private: c_void +} + +macro_rules! ifnull { + ($a:expr, $b:expr) => { + if $a.is_null() { $b } else { $a } + } +} + +struct Library(*mut c_void); + +impl Library { + fn open(name: &'static str) -> Library { + let flags = RTLD_LAZY | RTLD_GLOBAL; + let flags_noload = flags | RTLD_NOLOAD; + let name = CString::new(name).unwrap(); + let name = name.as_ptr(); + + Library(unsafe { + ifnull!(dlopen(name, flags_noload), dlopen(name, flags)) + }) + } + + fn get(&self, name: &'static str) -> *mut c_void { + let name = CString::new(name).unwrap(); + unsafe { dlsym(self.0, name.as_ptr()) } + } +} + +impl Drop for Library { + fn drop(&mut self) { + unsafe { dlclose(self.0); } + } +} + +unsafe impl Sync for Library {} +unsafe impl Send for Library {} + +lazy_static! { + static ref LIBRARY: Library = { + Library::open("libudev.so.1") + }; +} + +pub struct Symbol<T> { + ptr: *mut c_void, + pd: marker::PhantomData<T> +} + +impl<T> Symbol<T> { + fn new(ptr: *mut c_void) -> Self { + let default = Self::default as *mut c_void; + Self { ptr: ifnull!(ptr, default), pd: marker::PhantomData } + } + + // This is the default symbol, used whenever dlopen() fails. + // Users of this library are expected to check whether udev_new() returns + // a nullptr, and if so they MUST NOT call any other exported functions. + extern "C" fn default() -> *mut c_void { + ptr::null_mut() + } +} + +impl<T> ops::Deref for Symbol<T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { mem::transmute(&self.ptr) } + } +} + +unsafe impl<T: Sync + Send> Sync for Symbol<T> {} +unsafe impl<T: Sync + Send> Send for Symbol<T> {} + +macro_rules! define { + ($name:ident, $type:ty) => { + lazy_static! { + pub static ref $name : Symbol<$type> = { + Symbol::new(LIBRARY.get(stringify!($name))) + }; + } + }; +} + +// udev +define!(udev_new, extern "C" fn () -> *mut udev); +define!(udev_unref, extern "C" fn (*mut udev) -> *mut udev); + +// udev_list +define!(udev_list_entry_get_next, extern "C" fn (*mut udev_list_entry) -> *mut udev_list_entry); +define!(udev_list_entry_get_name, extern "C" fn (*mut udev_list_entry) -> *const c_char); +define!(udev_list_entry_get_value, extern "C" fn (*mut udev_list_entry) -> *const c_char); + +// udev_device +define!(udev_device_ref, extern "C" fn (*mut udev_device) -> *mut udev_device); +define!(udev_device_unref, extern "C" fn (*mut udev_device) -> *mut udev_device); +define!(udev_device_new_from_syspath, extern "C" fn (*mut udev, *const c_char) -> *mut udev_device); +define!(udev_device_get_parent, extern "C" fn (*mut udev_device) -> *mut udev_device); +define!(udev_device_get_devpath, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_subsystem, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_devtype, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_syspath, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_sysname, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_sysnum, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_devnode, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_is_initialized, extern "C" fn (*mut udev_device) -> c_int); +define!(udev_device_get_properties_list_entry, extern "C" fn (*mut udev_device) -> *mut udev_list_entry); +define!(udev_device_get_property_value, extern "C" fn (*mut udev_device, *const c_char) -> *const c_char); +define!(udev_device_get_driver, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_devnum, extern "C" fn (*mut udev_device) -> dev_t); +define!(udev_device_get_action, extern "C" fn (*mut udev_device) -> *const c_char); +define!(udev_device_get_sysattr_value, extern "C" fn (*mut udev_device, *const c_char) -> *const c_char); +define!(udev_device_set_sysattr_value, extern "C" fn (*mut udev_device, *const c_char, *mut c_char) -> c_int); +define!(udev_device_get_sysattr_list_entry, extern "C" fn (*mut udev_device) -> *mut udev_list_entry); +define!(udev_device_get_seqnum, extern "C" fn (*mut udev_device) -> c_ulonglong); + +// udev_monitor +define!(udev_monitor_ref, extern "C" fn (*mut udev_monitor) -> *mut udev_monitor); +define!(udev_monitor_unref, extern "C" fn (*mut udev_monitor) -> *mut udev_monitor); +define!(udev_monitor_new_from_netlink, extern "C" fn (*mut udev, *const c_char) -> *mut udev_monitor); +define!(udev_monitor_enable_receiving, extern "C" fn (*mut udev_monitor) -> c_int); +define!(udev_monitor_get_fd, extern "C" fn (*mut udev_monitor) -> c_int); +define!(udev_monitor_receive_device, extern "C" fn (*mut udev_monitor) -> *mut udev_device); +define!(udev_monitor_filter_add_match_subsystem_devtype, extern "C" fn (*mut udev_monitor, *const c_char, *const c_char) -> c_int); +define!(udev_monitor_filter_add_match_tag, extern "C" fn (*mut udev_monitor, *const c_char) -> c_int); +define!(udev_monitor_filter_remove, extern "C" fn (*mut udev_monitor) -> c_int); + +// udev_enumerate +define!(udev_enumerate_unref, extern "C" fn (*mut udev_enumerate) -> *mut udev_enumerate); +define!(udev_enumerate_new, extern "C" fn (*mut udev) -> *mut udev_enumerate); +define!(udev_enumerate_add_match_subsystem, extern "C" fn (*mut udev_enumerate, *const c_char) -> c_int); +define!(udev_enumerate_add_nomatch_subsystem, extern "C" fn (*mut udev_enumerate, *const c_char) -> c_int); +define!(udev_enumerate_add_match_sysattr, extern "C" fn (*mut udev_enumerate, *const c_char, *const c_char) -> c_int); +define!(udev_enumerate_add_nomatch_sysattr, extern "C" fn (*mut udev_enumerate, *const c_char, *const c_char) -> c_int); +define!(udev_enumerate_add_match_property, extern "C" fn (*mut udev_enumerate, *const c_char, *const c_char) -> c_int); +define!(udev_enumerate_add_match_tag, extern "C" fn (*mut udev_enumerate, *const c_char) -> c_int); +define!(udev_enumerate_add_match_parent, extern "C" fn (*mut udev_enumerate, *mut udev_device) -> c_int); +define!(udev_enumerate_add_match_is_initialized, extern "C" fn (*mut udev_enumerate) -> c_int); +define!(udev_enumerate_add_match_sysname, extern "C" fn (*mut udev_enumerate, *const c_char) -> c_int); +define!(udev_enumerate_add_syspath, extern "C" fn (*mut udev_enumerate, *const c_char) -> c_int); +define!(udev_enumerate_scan_devices, extern "C" fn (*mut udev_enumerate) -> c_int); +define!(udev_enumerate_get_list_entry, extern "C" fn (*mut udev_enumerate) -> *mut udev_list_entry); |