libseat-0.2.3/.cargo_vcs_info.json0000644000000001360000000000100124610ustar { "git": { "sha1": "2d46bdabc41bbcf7b67032693d37241736e69d04" }, "path_in_vcs": "" }libseat-0.2.3/.gitignore000064400000000000000000000000211046102023000132320ustar 00000000000000target Cargo.locklibseat-0.2.3/Cargo.lock0000644000000072540000000000100104440ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "errno" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", "windows-sys", ] [[package]] name = "errno-dragonfly" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" dependencies = [ "cc", "libc", ] [[package]] name = "libc" version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libseat" version = "0.2.3" dependencies = [ "cc", "errno", "libseat-sys", "log", "pkg-config", ] [[package]] name = "libseat-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "134621e50557e8698a96ccff3eadbc6f4b449d5d12f8aa48fcef8d40b4b02725" dependencies = [ "pkg-config", ] [[package]] name = "log" version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" libseat-0.2.3/Cargo.toml0000644000000026530000000000100104650ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "libseat" version = "0.2.3" authors = ["Poly "] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Safe libseat bindings" documentation = "https://docs.rs/libseat" readme = "README.md" keywords = ["libseat"] license = "MIT" repository = "https://github.com/PolyMeilex/libseat-rs" [package.metadata.docs.rs] features = ["libseat-sys/docs_rs"] no-default-features = true [lib] name = "libseat" path = "src/lib.rs" [[example]] name = "simple" path = "examples/simple.rs" [dependencies.errno] version = "0.3.1" [dependencies.libseat-sys] version = "0.1.9" [dependencies.log] version = "0.4" [build-dependencies.cc] version = "1.0.68" optional = true [build-dependencies.pkg-config] version = "0.3.19" optional = true [features] custom_logger = [ "cc", "pkg-config", ] default = ["custom_logger"] docs_rs = ["libseat-sys/docs_rs"] libseat-0.2.3/Cargo.toml.orig000064400000000000000000000014301046102023000141360ustar 00000000000000[package] name = "libseat" description = "Safe libseat bindings" version = "0.2.3" authors = ["Poly "] edition = "2018" keywords = ["libseat"] license = "MIT" repository = "https://github.com/PolyMeilex/libseat-rs" documentation = "https://docs.rs/libseat" [dependencies] errno = "0.3.1" libseat-sys = { version = "0.1.9", path = "./libseat-sys" } log = "0.4" [features] default = ["custom_logger"] custom_logger = ["cc", "pkg-config"] # Used to disable linking in docs.rs enviroment docs_rs = ["libseat-sys/docs_rs"] [build-dependencies] cc = { version = "1.0.68", optional = true } pkg-config = { version = "0.3.19", optional = true } [[example]] name = "simple" [package.metadata.docs.rs] no-default-features = true features = ["libseat-sys/docs_rs"] libseat-0.2.3/README.md000064400000000000000000000005141046102023000125300ustar 00000000000000# libseat-rs ```rust let seat = Seat::open( |seat, event| match event { SeatEvent::Enable => { println!("Enable"); println!("Name: {}", seat.name()); } SeatEvent::Disable => { println!("Disable"); seat.disable().unwrap(); } }, None, ) ``` libseat-0.2.3/build.rs000064400000000000000000000007111046102023000127150ustar 00000000000000#[cfg(not(feature = "custom_logger"))] fn main() {} #[cfg(feature = "custom_logger")] fn main() { let library = pkg_config::probe_library("libseat").unwrap(); let mut builder = cc::Build::new(); builder .file("./log_handler/log_handler.c") .flag("-Wno-unused-parameter") .include("/usr/local/include"); for i in &library.include_paths { builder.include(i); } builder.compile("libpreformatedlog"); } libseat-0.2.3/examples/simple.rs000064400000000000000000000015001046102023000147220ustar 00000000000000use libseat::{Seat, SeatEvent}; use std::{cell::RefCell, rc::Rc}; fn main() { let active = Rc::new(RefCell::new(false)); let seat = { let active = active.clone(); Seat::open(move |seat, event| match event { SeatEvent::Enable => { println!("Enable"); println!("Name: {}", seat.name()); *active.borrow_mut() = true; } SeatEvent::Disable => { println!("Disable"); *active.borrow_mut() = false; seat.disable().unwrap(); } }) }; if let Ok(mut seat) = seat { while !(*active.borrow()) { println!("waiting for activation...n"); seat.dispatch(-1).unwrap(); } // Close seat drop(seat); } } libseat-0.2.3/log_handler/log_handler.c000064400000000000000000000025131046102023000161520ustar 00000000000000#include #include #include #include #include "log_handler.h" static void noop_handler(enum libseat_log_level level, const char *msg, const void *userdata) { } static LogHandler current_log_handler = noop_handler; static const void *current_userdata = NULL; int str_length(const char *format, va_list args) { va_list argcopy; va_copy(argcopy, args); int retval = vsnprintf(NULL, 0, format, argcopy); va_end(argcopy); return retval; } static void formater_handler(enum libseat_log_level level, const char *fmt, va_list args) { if (level > LIBSEAT_LOG_LEVEL_LAST) { level = LIBSEAT_LOG_LEVEL_LAST; } int length = str_length(fmt, args); if (length >= 0) { // +1 for null terminator length += 1; char *buffer = (char *)malloc(length * sizeof(char)); vsnprintf(buffer, length, fmt, args); current_log_handler(level, buffer, current_userdata); free(buffer); } } void init_preformated_log_handler(LogHandler handler, const void *userdata) { current_userdata = userdata; current_log_handler = handler; libseat_set_log_handler(formater_handler); } void drop_preformated_log_handler() { libseat_set_log_handler(NULL); current_userdata = NULL; current_log_handler = noop_handler; }libseat-0.2.3/log_handler/log_handler.h000064400000000000000000000003231046102023000161540ustar 00000000000000typedef void (*LogHandler)(enum libseat_log_level level, const char *msg, const void *userdata); void init_preformated_log_handler(LogHandler handler, const void *userdata); void drop_preformated_log_handler();libseat-0.2.3/src/ffi_seat_listener.rs000064400000000000000000000026331046102023000160770ustar 00000000000000use libseat_sys as sys; use crate::{SeatEvent, SeatListener, SeatRef}; use std::ptr::NonNull; /// The seat has been enabled, and is now valid for use. Re-open all seat /// devices to ensure that they are operational, as existing fds may have /// had their functionality blocked or revoked. extern "C" fn enable_seat(seat: *mut sys::libseat, data: *mut std::os::raw::c_void) { let data = data as *mut SeatListener; let data = unsafe { &mut *data }; let mut seat = unsafe { SeatRef(NonNull::new_unchecked(seat)) }; (data.callback)(&mut seat, SeatEvent::Enable); } /// The seat has been disabled. This event signals that the application /// is going to lose its seat access. The event *must* be acknowledged /// with libseat_disable_seat shortly after receiving this event. /// /// If the recepient fails to acknowledge the event in time, seat devices /// may be forcibly revoked by the seat provider. extern "C" fn disable_seat(seat: *mut sys::libseat, data: *mut std::os::raw::c_void) { let data = data as *mut SeatListener; let data = unsafe { &mut *data }; let mut seat = unsafe { SeatRef(NonNull::new_unchecked(seat)) }; (data.callback)(&mut seat, SeatEvent::Disable); } /// A seat event listener, given to libseat_open_seat. pub static mut FFI_SEAT_LISTENER: sys::libseat_seat_listener = sys::libseat_seat_listener { enable_seat: Some(enable_seat), disable_seat: Some(disable_seat), }; libseat-0.2.3/src/lib.rs000064400000000000000000000152321046102023000131570ustar 00000000000000use libseat_sys as sys; use errno::{errno, Errno}; use std::{ ffi::CString, mem::MaybeUninit, ops::{Deref, DerefMut}, os::unix::io::{AsFd, BorrowedFd, RawFd}, path::Path, ptr::NonNull, }; mod ffi_seat_listener; use ffi_seat_listener::FFI_SEAT_LISTENER; mod log; pub use self::log::*; #[cfg(feature = "custom_logger")] mod log_handler; #[cfg(feature = "custom_logger")] use log_handler::*; #[derive(Debug, Clone, Copy)] pub enum SeatEvent { Enable, Disable, } type SeatListenerCallback = dyn FnMut(&mut SeatRef, SeatEvent); struct SeatListener { callback: Box, } impl std::fmt::Debug for SeatListener { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("UserSeatListener").finish() } } #[derive(Debug)] pub struct Seat { inner: SeatRef, _seat_listener: Box, #[cfg(feature = "custom_logger")] _logger: LogHandler, } impl Seat { /// Opens a seat, taking control of it if possible and returning a pointer to /// the libseat instance. If LIBSEAT_BACKEND is set, the specified backend is /// used. Otherwise, the first successful backend will be used. pub fn open(callback: C) -> Result where C: FnMut(&mut SeatRef, SeatEvent) + 'static, { #[cfg(feature = "custom_logger")] let _logger = LogHandler::new(); let user_listener = SeatListener { callback: Box::new(callback), }; let mut user_data = Box::new(user_listener); let seat = unsafe { sys::libseat_open_seat(&mut FFI_SEAT_LISTENER, user_data.as_mut() as *mut _ as _) }; NonNull::new(seat) .map(|nn| Self { inner: SeatRef(nn), _seat_listener: user_data, #[cfg(feature = "custom_logger")] _logger, }) .ok_or_else(errno) } } impl Drop for Seat { fn drop(&mut self) { // Closes the seat. This frees the libseat structure. unsafe { sys::libseat_close_seat(self.0.as_mut()) }; } } impl Deref for Seat { type Target = SeatRef; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for Seat { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } #[derive(Debug)] pub struct SeatRef(NonNull); impl SeatRef { /// Disables a seat, used in response to a disable_seat event. After disabling /// the seat, the seat devices must not be used until enable_seat is received, /// and all requests on the seat will fail during this period. pub fn disable(&mut self) -> Result<(), Errno> { if unsafe { sys::libseat_disable_seat(self.0.as_mut()) } == 0 { Ok(()) } else { Err(errno()) } } /// Opens a device on the seat, returning its device ID and fd /// /// This will only succeed if the seat is active and the device is of a type /// permitted for opening on the backend, such as drm and evdev. /// /// The device may be revoked in some situations, such as in situations where a /// seat session switch is being forced. pub fn open_device>(&mut self, path: &P) -> Result { let path = path.as_ref(); let string = path.as_os_str().to_str().unwrap(); let cstring = CString::new(string).unwrap(); let mut fd = MaybeUninit::uninit(); let id = unsafe { sys::libseat_open_device(self.0.as_mut(), cstring.as_ptr(), fd.as_mut_ptr()) }; if id != -1 { Ok(Device { id, fd: unsafe { fd.assume_init() }, }) } else { Err(errno()) } } /// Closes a device that has been opened on the seat using the device_id from /// libseat_open_device. pub fn close_device(&mut self, device: Device) -> Result<(), Errno> { if unsafe { sys::libseat_close_device(self.0.as_mut(), device.id) } == 0 { Ok(()) } else { Err(errno()) } } /// Retrieves the name of the seat that is currently made available through the /// provided libseat instance. pub fn name(&mut self) -> &str { unsafe { let cstr = sys::libseat_seat_name(self.0.as_mut()); let cstr = std::ffi::CStr::from_ptr(cstr as *const _); cstr.to_str().unwrap() } } /// Requests that the seat switches session to the specified session number. /// For seats that are VT-bound, the session number matches the VT number, and /// switching session results in a VT switch. /// /// A call to libseat_switch_session does not imply that a switch will occur, /// and the caller should assume that the session continues unaffected. pub fn switch_session(&mut self, session: i32) -> Result<(), Errno> { if unsafe { sys::libseat_switch_session(self.0.as_mut(), session) } == 0 { Ok(()) } else { Err(errno()) } } /// Retrieve the pollable connection fd for a given libseat instance. Used to /// poll the libseat connection for events that need to be dispatched. /// /// Returns a pollable fd on success. pub fn get_fd(&mut self) -> Result { let fd = unsafe { sys::libseat_get_fd(self.0.as_mut()) }; if fd == -1 { Err(errno()) } else { Ok(unsafe { BorrowedFd::borrow_raw(fd) }) } } /// Reads and dispatches events on the libseat connection fd. /// /// The specified timeout dictates how long libseat might wait for data if none /// is available: 0 means that no wait will occur, -1 means that libseat might /// wait indefinitely for data to arrive, while > 0 is the maximum wait in /// milliseconds that might occur. /// /// Returns a positive number signifying processed internal messages on success. /// Returns 0 if no messages were processed. Returns -1 and sets errno on error. pub fn dispatch(&mut self, timeout: i32) -> Result { let v = unsafe { sys::libseat_dispatch(self.0.as_mut(), timeout) }; if v == -1 { Err(errno()) } else { Ok(v) } } } /// Wrapper around the device id and fd of a libseat device. Opened with /// [SeatRef::open_device]. /// /// Use `AsFd` to access the file descriptor. The device should be closed /// with [SeatRef::close_device]. #[derive(Debug)] #[must_use] pub struct Device { id: i32, fd: RawFd, } impl AsFd for Device { fn as_fd(&self) -> BorrowedFd<'_> { unsafe { BorrowedFd::borrow_raw(self.fd) } } } libseat-0.2.3/src/log.rs000064400000000000000000000011571046102023000131730ustar 00000000000000use libseat_sys::{libseat_log_level, libseat_set_log_level}; #[repr(u32)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum LogLevel { Silent = 0, Error = 1, Info = 2, Debug = 3, Last = 4, } impl From for LogLevel { fn from(v: libseat_log_level) -> LogLevel { match v { 0 => LogLevel::Silent, 1 => LogLevel::Error, 2 => LogLevel::Info, 3 => LogLevel::Debug, _ => LogLevel::Last, } } } pub fn set_log_level(level: LogLevel) { unsafe { libseat_set_log_level(level as _) } } libseat-0.2.3/src/log_handler.rs000064400000000000000000000024321046102023000146650ustar 00000000000000use log::{debug, error, info, trace}; use std::{ ffi::CStr, os::raw::{c_char, c_void}, }; use crate::LogLevel; pub type LogHandlerFn = unsafe extern "C" fn(level: LogLevel, msg: *const c_char, data: *const c_void); extern "C" { pub fn init_preformated_log_handler(handler: LogHandlerFn, data: *const c_void); pub fn drop_preformated_log_handler(); } /// Custom LibSeat log handler #[derive(Debug)] pub struct LogHandler; impl LogHandler { pub fn new() -> Self { crate::set_log_level(LogLevel::Debug); unsafe { init_preformated_log_handler(ffi_handler, std::ptr::null()) }; Self } fn log(level: LogLevel, msg: &str) { match level { LogLevel::Silent => trace!("{}", msg), LogLevel::Error => error!("{}", msg), LogLevel::Info => info!("{}", msg), LogLevel::Debug | LogLevel::Last => debug!("{}", msg), } } } impl Drop for LogHandler { fn drop(&mut self) { unsafe { drop_preformated_log_handler() } } } extern "C" fn ffi_handler(level: LogLevel, msg: *const c_char, _data: *const c_void) { let cstr = unsafe { CStr::from_ptr(msg) }; match cstr.to_str() { Ok(msg) => LogHandler::log(level, msg), Err(err) => error!("{:?}", err), } }