1
0
Fork 0
forked from wry/wry

autocommit 2022-03-09 14:01:21 CET

This commit is contained in:
Julian Orth 2022-03-09 14:01:21 +01:00
parent aa0cb94143
commit 4df6b559b7
32 changed files with 1121 additions and 172 deletions

View file

@ -15,6 +15,9 @@ mod pixman;
#[path = "../src/xkbcommon/consts.rs"] #[path = "../src/xkbcommon/consts.rs"]
mod xkbcommon; mod xkbcommon;
#[path = "../src/libinput/consts.rs"]
mod libinput;
fn get_target() -> repc::Target { fn get_target() -> repc::Target {
let rustc_target = env::var("TARGET").unwrap(); let rustc_target = env::var("TARGET").unwrap();
repc::TARGET_MAP repc::TARGET_MAP
@ -193,6 +196,67 @@ fn write_egl_procs<W: Write>(f: &mut W) -> anyhow::Result<()> {
} }
pub fn main() -> anyhow::Result<()> { pub fn main() -> anyhow::Result<()> {
let mut f = open("libinput_tys.rs")?;
write_ty(
&mut f,
libinput::LIBINPUT_LOG_PRIORITY,
"libinput_log_priority",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_DEVICE_CAPABILITY,
"libinput_device_capability",
)?;
write_ty(&mut f, libinput::LIBINPUT_KEY_STATE, "libinput_key_state")?;
write_ty(&mut f, libinput::LIBINPUT_LED, "libinput_led")?;
write_ty(
&mut f,
libinput::LIBINPUT_BUTTON_STATE,
"libinput_button_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_POINTER_AXIS,
"libinput_pointer_axis",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_POINTER_AXIS_SOURCE,
"libinput_pointer_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_PAD_RING_AXIS_SOURCE,
"libinput_tablet_pad_ring_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_PAD_STRIP_AXIS_SOURCE,
"libinput_tablet_pad_strip_axis_source",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_TYPE,
"libinput_tablet_tool_type",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_PROXIMITY_STATE,
"libinput_tablet_tool_proximity_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_TABLET_TOOL_TIP_STATE,
"libinput_tablet_tool_tip_state",
)?;
write_ty(
&mut f,
libinput::LIBINPUT_SWITCH_STATE,
"libinput_switch_state",
)?;
write_ty(&mut f, libinput::LIBINPUT_SWITCH, "libinput_switch")?;
write_ty(&mut f, libinput::LIBINPUT_EVENT_TYPE, "libinput_event_type")?;
let mut f = open("pixman_tys.rs")?; let mut f = open("pixman_tys.rs")?;
write_ty(&mut f, pixman::FORMATS, "PixmanFormat")?; write_ty(&mut f, pixman::FORMATS, "PixmanFormat")?;
write_ty(&mut f, pixman::OPS, "PixmanOp")?; write_ty(&mut f, pixman::OPS, "PixmanOp")?;

View file

@ -13,23 +13,23 @@ pub enum AcceptorError {
#[error("XDG_RUNTIME_DIR ({0:?}) is too long to form a unix socket address")] #[error("XDG_RUNTIME_DIR ({0:?}) is too long to form a unix socket address")]
XrdTooLong(String), XrdTooLong(String),
#[error("Could not create a wayland socket")] #[error("Could not create a wayland socket")]
SocketFailed(#[source] std::io::Error), SocketFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not stat the existing socket")] #[error("Could not stat the existing socket")]
SocketStat(#[source] std::io::Error), SocketStat(#[source] crate::utils::oserror::OsError),
#[error("Could not start listening for incoming connections")] #[error("Could not start listening for incoming connections")]
ListenFailed(#[source] std::io::Error), ListenFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not open the lock file")] #[error("Could not open the lock file")]
OpenLockFile(#[source] std::io::Error), OpenLockFile(#[source] crate::utils::oserror::OsError),
#[error("Could not lock the lock file")] #[error("Could not lock the lock file")]
LockLockFile(#[source] std::io::Error), LockLockFile(#[source] crate::utils::oserror::OsError),
#[error("The wayland socket is in an error state")] #[error("The wayland socket is in an error state")]
ErrorEvent, ErrorEvent,
#[error("Could not accept new connections")] #[error("Could not accept new connections")]
AcceptFailed(#[source] std::io::Error), AcceptFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not spawn an event handler for a new connection")] #[error("Could not spawn an event handler for a new connection")]
SpawnFailed(#[source] ClientError), SpawnFailed(#[source] ClientError),
#[error("Could not bind the socket to an address")] #[error("Could not bind the socket to an address")]
BindFailed(#[source] std::io::Error), BindFailed(#[source] crate::utils::oserror::OsError),
#[error("All wayland addresses in the range 0..1000 are already in use")] #[error("All wayland addresses in the range 0..1000 are already in use")]
AddressesInUse, AddressesInUse,
#[error("The event loop caused an error")] #[error("The event loop caused an error")]

View file

@ -3,8 +3,8 @@ use crate::event_loop::{EventLoop, EventLoopError};
use crate::utils::copyhashmap::CopyHashMap; use crate::utils::copyhashmap::CopyHashMap;
use crate::utils::numcell::NumCell; use crate::utils::numcell::NumCell;
use crate::wheel::{Wheel, WheelError}; use crate::wheel::{Wheel, WheelError};
pub use fd::{AsyncFd, FdStatus};
use fd::AsyncFdData; use fd::AsyncFdData;
pub use fd::{AsyncFd, FdStatus};
use queue::{DispatchQueue, Dispatcher}; use queue::{DispatchQueue, Dispatcher};
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::future::Future; use std::future::Future;
@ -562,7 +562,10 @@ mod fd {
let res = self.el.modify(self.id, events); let res = self.el.modify(self.id, events);
if res.is_err() { if res.is_err() {
if let Err(e) = self.el.remove(self.id) { if let Err(e) = self.el.remove(self.id) {
log::error!("Fatal error: Cannot remove file descriptor from event loop: {:?}", e); log::error!(
"Fatal error: Cannot remove file descriptor from event loop: {:?}",
e
);
self.el.stop(); self.el.stop();
} }
} }

View file

@ -1,12 +1,19 @@
mod input;
mod monitor;
use crate::async_engine::AsyncFd;
use crate::dbus::DbusError; use crate::dbus::DbusError;
use crate::libinput::device::RegisteredDevice;
use crate::libinput::{LibInput, LibInputAdapter, LibInputError};
use crate::logind::{LogindError, Session}; use crate::logind::{LogindError, Session};
use crate::{AsyncQueue, ErrorFmt, State, Udev}; use crate::udev::{UdevError, UdevMonitor};
use crate::utils::copyhashmap::CopyHashMap;
use crate::{AsyncQueue, CloneCell, ErrorFmt, NumCell, State, Udev};
use std::cell::{Cell, RefCell};
use std::ffi::{CStr, CString};
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use uapi::OwnedFd; use uapi::{c, OwnedFd};
use crate::async_engine::{AsyncFd, FdStatus};
use crate::libinput::{LibInput, LibInputError};
use crate::udev::{UdevError, UdevMonitor};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum MetalError { pub enum MetalError {
@ -16,12 +23,14 @@ pub enum MetalError {
LogindSession(#[source] LogindError), LogindSession(#[source] LogindError),
#[error("Could not take control of the logind session")] #[error("Could not take control of the logind session")]
TakeControl(#[source] LogindError), TakeControl(#[source] LogindError),
#[error("Could not enumerate devices")]
Enumerate(#[source] Box<Self>),
#[error(transparent)] #[error(transparent)]
Udev(#[from] UdevError), Udev(#[from] UdevError),
#[error(transparent)] #[error(transparent)]
LibInput(#[from] LibInputError), LibInput(#[from] LibInputError),
#[error("Dupfd failed")] #[error("Dupfd failed")]
Dup(#[source] std::io::Error), Dup(#[source] crate::utils::oserror::OsError),
} }
pub async fn run(state: Rc<State>) { pub async fn run(state: Rc<State>) {
@ -30,6 +39,18 @@ pub async fn run(state: Rc<State>) {
} }
} }
struct MetalBackend {
state: Rc<State>,
udev: Rc<Udev>,
monitor: Rc<UdevMonitor>,
monitor_fd: AsyncFd,
libinput: Rc<LibInput>,
libinput_fd: AsyncFd,
device_holder: Rc<DeviceHolder>,
session: Session,
ids: NumCell<u64>,
}
async fn run_(state: Rc<State>) -> Result<(), MetalError> { async fn run_(state: Rc<State>) -> Result<(), MetalError> {
let socket = match state.dbus.system() { let socket = match state.dbus.system() {
Ok(s) => s, Ok(s) => s,
@ -39,90 +60,83 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
Ok(s) => s, Ok(s) => s,
Err(e) => return Err(MetalError::LogindSession(e)), Err(e) => return Err(MetalError::LogindSession(e)),
}; };
// if let Err(e) = session.take_control().await { if let Err(e) = session.take_control().await {
// return Err(MetalError::TakeControl(e)); return Err(MetalError::TakeControl(e));
// } }
let device_holder = Rc::new(DeviceHolder {
input_devices: Default::default(),
input_devices_: Default::default(),
});
let udev = Rc::new(Udev::new()?); let udev = Rc::new(Udev::new()?);
let monitor = Rc::new(udev.create_monitor()?); let monitor = Rc::new(udev.create_monitor()?);
monitor.add_match_subsystem_devtype(Some("input"), None)?; monitor.add_match_subsystem_devtype(Some("input"), None)?;
monitor.enable_receiving()?; monitor.enable_receiving()?;
let libinput = Rc::new(LibInput::new()?); let libinput = Rc::new(LibInput::new(device_holder.clone())?);
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) { let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(), Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
Err(e) => return Err(MetalError::Dup(e.into())), Err(e) => return Err(MetalError::Dup(e.into())),
}; };
let libinput_fd = match uapi::fcntl_dupfd_cloexec(libinput.fd(), 0) {
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
Err(e) => return Err(MetalError::Dup(e.into())),
};
let metal = Rc::new(MetalBackend { let metal = Rc::new(MetalBackend {
state: state.clone(), state: state.clone(),
udev, udev,
monitor, monitor,
monitor_fd, monitor_fd,
libinput, libinput,
libinput_fd,
device_holder,
session,
ids: Default::default(),
}); });
let _monitor = state.eng.spawn(metal.clone().monitor_devices()); let _monitor = state.eng.spawn(metal.clone().monitor_devices());
let mut queue = AsyncQueue::<String>::new(); let _events = state.eng.spawn(metal.clone().handle_libinput_events());
if let Err(e) = metal.enumerate_devices() {
return Err(MetalError::Enumerate(Box::new(e)));
}
let queue = AsyncQueue::<String>::new();
queue.pop().await; queue.pop().await;
Ok(()) Ok(())
// let libinput_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
// Ok(m) => m,
// Err(e) => Err(MetalError::Dup(e.into())),
// };
// let mut enumerate = udev.create_enumerate()?;
// enumerate.add_match_subsystem("input")?;
// enumerate.scan_devices()?;
// let mut entry_opt = enumerate.get_list_entry()?;
// while let Some(entry) = entry_opt {
// let device = udev.create_device_from_syspath(entry.name()?)?;
// if device.sysname()?.to_bytes().starts_with(b"event") {
// let devnode = device.devnode()?;
// }
// }
} }
struct MetalBackend { struct MetalDevice {
state: Rc<State>, slot: usize,
udev: Rc<Udev>, device_id: u64,
monitor: Rc<UdevMonitor>, devnum: c::dev_t,
monitor_fd: AsyncFd, fd: CloneCell<Option<Rc<OwnedFd>>>,
libinput: Rc<LibInput>, inputdev: Cell<Option<RegisteredDevice>>,
libinput_fd: AsyncFd, devnode: CString,
sysname: CString,
}
struct DeviceHolder {
input_devices: CopyHashMap<c::dev_t, Rc<MetalDevice>>,
input_devices_: RefCell<Vec<Option<Rc<MetalDevice>>>>,
}
impl LibInputAdapter for DeviceHolder {
fn open(&self, path: &CStr) -> Result<OwnedFd, LibInputError> {
let stat = match uapi::stat(path) {
Ok(s) => s,
Err(e) => return Err(LibInputError::Stat(e.into())),
};
match self.input_devices.get(&stat.st_rdev) {
Some(d) => match d.fd.get() {
Some(fd) => match uapi::fcntl_dupfd_cloexec(fd.raw(), 0) {
Ok(fd) => Ok(fd),
Err(e) => Err(LibInputError::DupFd(e.into())),
},
_ => Err(LibInputError::DeviceUnavailable),
},
_ => Err(LibInputError::DeviceUnavailable),
}
}
} }
impl MetalBackend { impl MetalBackend {
async fn monitor_devices(self: Rc<Self>) { fn id(&self) -> u64 {
loop { self.ids.fetch_add(1)
match self.monitor_fd.readable().await {
Err(e) => {
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => { },
}
while let Some(dev) = self.monitor.receive_device() {
log::info!("x {:?}", dev.devnode());
}
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
}
async fn handle_libinput_events(self: Rc<Self>) {
loop {
match self.libinput_fd.readable().await {
Err(e) => {
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => { },
}
self.libinput.fd()
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
} }
} }

View file

@ -0,0 +1,55 @@
use crate::async_engine::FdStatus;
use crate::libinput::consts::LIBINPUT_EVENT_KEYBOARD_KEY;
use crate::libinput::event::LibInputEvent;
use crate::metal::MetalBackend;
use crate::ErrorFmt;
use std::rc::Rc;
impl MetalBackend {
pub async fn handle_libinput_events(self: Rc<Self>) {
loop {
match self.libinput_fd.readable().await {
Err(e) => {
log::error!(
"Cannot wait for libinput fd to become readable: {}",
ErrorFmt(e)
);
break;
}
Ok(FdStatus::Err) => {
log::error!("libinput fd fd is in an error state");
break;
}
_ => {}
}
if let Err(e) = self.libinput.dispatch() {
log::error!("Could not dispatch libinput events: {}", ErrorFmt(e));
break;
}
while let Some(event) = self.libinput.event() {
self.handle_event(event);
}
}
log::error!("Libinput task exited. Future input events will be ignored.");
}
fn handle_event(self: &Rc<Self>, event: LibInputEvent) {
match event.ty() {
LIBINPUT_EVENT_KEYBOARD_KEY => self.handle_keyboard_event(event),
_ => {}
}
}
fn handle_keyboard_event(self: &Rc<Self>, event: LibInputEvent) {
let event = match event.keyboard_event() {
Some(event) => event,
_ => return,
};
log::info!(
"key: {}, state: {:?}, time: {}",
event.key(),
event.key_state(),
event.time_usec()
);
}
}

View file

@ -0,0 +1,131 @@
use crate::async_engine::FdStatus;
use crate::dbus::TRUE;
use crate::metal::{MetalBackend, MetalDevice, MetalError};
use crate::udev::UdevDevice;
use crate::ErrorFmt;
use std::rc::Rc;
impl MetalBackend {
pub async fn monitor_devices(self: Rc<Self>) {
loop {
match self.monitor_fd.readable().await {
Err(e) => {
log::error!(
"Cannot wait for udev_monitor to become readable: {}",
ErrorFmt(e)
);
break;
}
Ok(FdStatus::Err) => {
log::error!("udev_monitor fd is in an error state");
break;
}
_ => {}
}
while let Some(dev) = self.monitor.receive_device() {
log::info!("x {:?}", dev.devnode());
}
}
log::error!("Monitor task exited. Future hotplug events will be ignored.");
}
pub fn enumerate_devices(self: &Rc<Self>) -> Result<(), MetalError> {
let mut enumerate = self.udev.create_enumerate()?;
enumerate.add_match_subsystem("input")?;
enumerate.scan_devices()?;
let mut entry_opt = enumerate.get_list_entry()?;
while let Some(entry) = entry_opt.take() {
'inner: {
let device = match self.udev.create_device_from_syspath(entry.name()) {
Ok(d) => d,
_ => break 'inner,
};
let sysname = match device.sysname() {
Ok(s) => s,
_ => break 'inner,
};
if sysname.to_bytes().starts_with(b"event") {
self.add_input_device(&device);
}
}
entry_opt = entry.next();
}
Ok(())
}
fn add_input_device(self: &Rc<Self>, dev: &UdevDevice) {
let slf = self.clone();
let device_id = self.id();
let devnum = dev.devnum();
let devnode = match dev.devnode() {
Ok(n) => n,
Err(e) => {
log::error!("Could not retrieve devnode of udev device: {}", ErrorFmt(e));
return;
}
};
let sysname = match dev.sysname() {
Ok(n) => n,
Err(e) => {
log::error!("Could not retrieve sysname of udev device: {}", ErrorFmt(e));
return;
}
};
let mut slots = self.device_holder.input_devices_.borrow_mut();
let slot = 'slot: {
for (i, s) in slots.iter().enumerate() {
if s.is_none() {
break 'slot i;
}
}
slots.push(None);
slots.len() - 1
};
let dev = Rc::new(MetalDevice {
slot,
device_id,
devnum,
fd: Default::default(),
inputdev: Default::default(),
devnode: devnode.to_owned(),
sysname: sysname.to_owned(),
});
slots[slot] = Some(dev.clone());
self.device_holder.input_devices.set(devnum, dev);
self.session.get_device(devnum, move |res| {
let id = &slf.device_holder.input_devices;
let mut slots = slf.device_holder.input_devices_.borrow_mut();
let dev = 'dev: {
if let Some(dev) = id.get(&devnum) {
if dev.device_id == device_id {
break 'dev dev;
}
}
return;
};
let res = match res {
Ok(r) => r,
Err(e) => {
log::error!("Could not take control of input device: {}", ErrorFmt(e));
slots[dev.slot] = None;
id.remove(&devnum);
return;
}
};
if res.inactive == TRUE {
return;
}
dev.fd.set(Some(res.fd.clone()));
let inputdev = match slf.libinput.open(dev.devnode.as_c_str()) {
Ok(d) => d,
Err(_) => {
slots[dev.slot] = None;
id.remove(&devnum);
return;
}
};
inputdev.device().set_slot(slot);
dev.inputdev.set(Some(inputdev));
});
}
}

View file

@ -87,7 +87,7 @@ impl Clients {
Err(e) => { Err(e) => {
log::error!( log::error!(
"Cannot determine peer credentials of new connection: {:?}", "Cannot determine peer credentials of new connection: {:?}",
std::io::Error::from(e) crate::utils::oserror::OsError::from(e)
); );
return Ok(()); return Ok(());
} }

View file

@ -10,11 +10,11 @@ use uapi::c::raise;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ClientMemError { pub enum ClientMemError {
#[error("Could not install the sigbus handler")] #[error("Could not install the sigbus handler")]
SigactionFailed(#[source] std::io::Error), SigactionFailed(#[source] crate::utils::oserror::OsError),
#[error("A SIGBUS occurred while accessing mapped memory")] #[error("A SIGBUS occurred while accessing mapped memory")]
Sigbus, Sigbus,
#[error("mmap failed")] #[error("mmap failed")]
MmapFailed(#[source] std::io::Error), MmapFailed(#[source] crate::utils::oserror::OsError),
} }
pub struct ClientMem { pub struct ClientMem {

View file

@ -67,13 +67,13 @@ pub enum DbusError {
#[error("Variant has an invalid type")] #[error("Variant has an invalid type")]
InvalidVariantType, InvalidVariantType,
#[error("Could not create a socket")] #[error("Could not create a socket")]
Socket(#[source] std::io::Error), Socket(#[source] crate::utils::oserror::OsError),
#[error("Could not connect")] #[error("Could not connect")]
Connect(#[source] std::io::Error), Connect(#[source] crate::utils::oserror::OsError),
#[error("Could not write to the dbus socket")] #[error("Could not write to the dbus socket")]
WriteError(#[source] std::io::Error), WriteError(#[source] crate::utils::oserror::OsError),
#[error("Could not read from the dbus socket")] #[error("Could not read from the dbus socket")]
ReadError(#[source] std::io::Error), ReadError(#[source] crate::utils::oserror::OsError),
#[error("timeout")] #[error("timeout")]
AsyncError(#[source] Box<AsyncError>), AsyncError(#[source] Box<AsyncError>),
#[error("Server did not accept our authentication")] #[error("Server did not accept our authentication")]

View file

@ -49,7 +49,11 @@ impl Outgoing {
return; return;
} }
if let Err(e) = self.socket.fd.writable().await { if let Err(e) = self.socket.fd.writable().await {
log::error!("{}: Cannot wait for fd to become readable: {}", self.socket.bus_name, ErrorFmt(e)); log::error!(
"{}: Cannot wait for fd to become readable: {}",
self.socket.bus_name,
ErrorFmt(e)
);
self.socket.kill(); self.socket.kill();
return; return;
} }

View file

@ -12,13 +12,13 @@ use uapi::{c, Errno, OwnedFd, Ustring};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum DrmError { pub enum DrmError {
#[error("Could not reopen a node")] #[error("Could not reopen a node")]
ReopenNode(#[source] std::io::Error), ReopenNode(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the render node name")] #[error("Could not retrieve the render node name")]
RenderNodeName, RenderNodeName,
#[error("Could not retrieve the device node name")] #[error("Could not retrieve the device node name")]
DeviceNodeName, DeviceNodeName,
#[error("Could not retrieve device")] #[error("Could not retrieve device")]
GetDevice(#[source] std::io::Error), GetDevice(#[source] crate::utils::oserror::OsError),
} }
#[allow(dead_code)] #[allow(dead_code)]

View file

@ -9,17 +9,17 @@ use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum EventLoopError { pub enum EventLoopError {
#[error("Could not create an epoll fd: {0}")] #[error("Could not create an epoll fd: {0}")]
CreateFailed(std::io::Error), CreateFailed(crate::utils::oserror::OsError),
#[error("epoll_wait failed: {0}")] #[error("epoll_wait failed: {0}")]
WaitFailed(std::io::Error), WaitFailed(crate::utils::oserror::OsError),
#[error("A dispatcher returned a fatal error: {0}")] #[error("A dispatcher returned a fatal error: {0}")]
DispatcherError(Box<dyn std::error::Error>), DispatcherError(Box<dyn std::error::Error>),
#[error("Could not insert an fd to wait on: {0}")] #[error("Could not insert an fd to wait on: {0}")]
InsertFailed(std::io::Error), InsertFailed(crate::utils::oserror::OsError),
#[error("Could not modify an fd to wait on: {0}")] #[error("Could not modify an fd to wait on: {0}")]
ModifyFailed(std::io::Error), ModifyFailed(crate::utils::oserror::OsError),
#[error("Could not remove an fd to wait on: {0}")] #[error("Could not remove an fd to wait on: {0}")]
RemoveFailed(std::io::Error), RemoveFailed(crate::utils::oserror::OsError),
#[error("Entry is not registered")] #[error("Entry is not registered")]
NoEntry, NoEntry,
#[error("Event loop is already destroyed")] #[error("Event loop is already destroyed")]

View file

@ -43,9 +43,9 @@ struct PidfdHandoff {
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ForkerError { pub enum ForkerError {
#[error("Could not create a socketpair")] #[error("Could not create a socketpair")]
Socketpair(#[source] std::io::Error), Socketpair(#[source] crate::utils::oserror::OsError),
#[error("Could not fork")] #[error("Could not fork")]
Fork(#[source] std::io::Error), Fork(#[source] crate::utils::oserror::OsError),
#[error("Could not read the next message")] #[error("Could not read the next message")]
ReadFailed(#[source] BufFdError), ReadFailed(#[source] BufFdError),
#[error("Could not write the next message")] #[error("Could not write the next message")]
@ -235,7 +235,10 @@ impl ForkerProxy {
async fn check_process(self: Rc<Self>, state: Rc<State>) { async fn check_process(self: Rc<Self>, state: Rc<State>) {
let pidfd = state.eng.fd(&self.pidfd).unwrap(); let pidfd = state.eng.fd(&self.pidfd).unwrap();
if let Err(e) = pidfd.readable().await { if let Err(e) = pidfd.readable().await {
log::error!("Cannot wait for the forker pidfd to become readable: {}", ErrorFmt(e)); log::error!(
"Cannot wait for the forker pidfd to become readable: {}",
ErrorFmt(e)
);
} else { } else {
let _ = uapi::waitpid(self.pid, 0); let _ = uapi::waitpid(self.pid, 0);
} }
@ -417,7 +420,10 @@ impl Forker {
let spawn = self.ae.spawn(async move { let spawn = self.ae.spawn(async move {
let read = slf.ae.fd(&Rc::new(read)).unwrap(); let read = slf.ae.fd(&Rc::new(read)).unwrap();
if let Err(e) = read.readable().await { if let Err(e) = read.readable().await {
log::error!("Cannot wait for the child fd to become readable: {}", ErrorFmt(e)); log::error!(
"Cannot wait for the child fd to become readable: {}",
ErrorFmt(e)
);
} else { } else {
let mut s = String::new(); let mut s = String::new();
let _ = Fd::new(read.raw()).read_to_string(&mut s); let _ = Fd::new(read.raw()).read_to_string(&mut s);
@ -476,9 +482,9 @@ impl Forker {
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum SpawnError { enum SpawnError {
#[error("exec failed")] #[error("exec failed")]
Exec(#[source] std::io::Error), Exec(#[source] crate::utils::oserror::OsError),
#[error("Could not unset cloexec flag")] #[error("Could not unset cloexec flag")]
Cloexec(#[source] std::io::Error), Cloexec(#[source] crate::utils::oserror::OsError),
} }
fn setup_fds(mut socket: OwnedFd) -> OwnedFd { fn setup_fds(mut socket: OwnedFd) -> OwnedFd {

View file

@ -125,9 +125,9 @@ pub enum WlKeyboardError {
#[error("Could not process a `release` request")] #[error("Could not process a `release` request")]
ReleaseError(#[from] ReleaseError), ReleaseError(#[from] ReleaseError),
#[error("Could not create a keymap memfd")] #[error("Could not create a keymap memfd")]
KeymapMemfd(#[source] std::io::Error), KeymapMemfd(#[source] crate::utils::oserror::OsError),
#[error("Could not copy the keymap")] #[error("Could not copy the keymap")]
KeymapCopy(#[source] std::io::Error), KeymapCopy(#[source] crate::utils::oserror::OsError),
} }
efrom!(WlKeyboardError, ClientError, ClientError); efrom!(WlKeyboardError, ClientError, ClientError);

View file

@ -1,31 +1,31 @@
use crate::udev::Udev; #![allow(non_camel_case_types)]
pub mod consts;
pub mod device;
pub mod event;
mod sys;
use crate::libinput::consts::{
LogPriority, LIBINPUT_LOG_PRIORITY_DEBUG, LIBINPUT_LOG_PRIORITY_ERROR,
LIBINPUT_LOG_PRIORITY_INFO,
};
use crate::libinput::device::RegisteredDevice;
use crate::libinput::event::LibInputEvent;
use crate::libinput::sys::{
libinput, libinput_device_ref, libinput_dispatch, libinput_get_event, libinput_get_fd,
libinput_interface, libinput_log_priority, libinput_log_set_handler, libinput_log_set_priority,
libinput_path_add_device, libinput_path_create_context, libinput_unref,
};
use crate::udev::UdevError;
use crate::utils::oserror::OsError;
use crate::utils::ptr_ext::PtrExt; use crate::utils::ptr_ext::PtrExt;
use std::ops::DerefMut; use crate::utils::vasprintf::vasprintf_;
use crate::ErrorFmt;
use bstr::ByteSlice;
use std::ffi::{CStr, VaList};
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use uapi::{c, OwnedFd}; use uapi::{c, Errno, IntoUstr, OwnedFd};
#[link(name = "input")]
extern "C" {
type libinput;
fn libinput_path_create_context(
interface: *const libinput_interface,
user_data: *mut c::c_void,
) -> *mut libinput;
fn libinput_unref(libinput: *mut libinput) -> *mut libinput;
fn libinput_get_fd(libinput: *mut libinput) -> c::c_int;
}
#[repr(C)]
struct libinput_interface {
open_restricted: unsafe extern "C" fn(
path: *const c::c_char,
flags: c::c_int,
user_data: *mut c::c_void,
) -> c::c_int,
close_restricted: unsafe extern "C" fn(fd: c::c_int, user_data: *mut c::c_void),
}
static INTERFACE: libinput_interface = libinput_interface { static INTERFACE: libinput_interface = libinput_interface {
open_restricted, open_restricted,
@ -34,23 +34,47 @@ static INTERFACE: libinput_interface = libinput_interface {
unsafe extern "C" fn open_restricted( unsafe extern "C" fn open_restricted(
path: *const c::c_char, path: *const c::c_char,
flags: c::c_int, _flags: c::c_int,
user_data: *mut c::c_void, user_data: *mut c::c_void,
) -> c::c_int { ) -> c::c_int {
let ud = (user_data as *const UserData).deref(); let ud = (user_data as *const UserData).deref();
-1 match ud.adapter.open(CStr::from_ptr(path)) {
Ok(f) => f.unwrap(),
Err(e) => {
log::error!("Could not open device for libinput: {}", ErrorFmt(e));
-1
}
}
} }
unsafe extern "C" fn close_restricted(fd: c::c_int, _user_data: *mut c::c_void) { unsafe extern "C" fn close_restricted(fd: c::c_int, _user_data: *mut c::c_void) {
drop(OwnedFd::new(fd)); drop(OwnedFd::new(fd));
} }
struct UserData {} struct UserData {
adapter: Rc<dyn LibInputAdapter>,
}
pub trait LibInputAdapter {
fn open(&self, path: &CStr) -> Result<OwnedFd, LibInputError>;
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum LibInputError { pub enum LibInputError {
#[error("Could not create a libinput instance")] #[error("Could not create a libinput instance")]
New, New,
#[error("Could not open a libinput device")]
Open,
#[error("Could not dispatch libinput events")]
Dispatch(#[source] OsError),
#[error("The requested device is not available")]
DeviceUnavailable,
#[error("Dupfd failed")]
DupFd(#[source] OsError),
#[error("The udev subsystem produced an error")]
Udev(#[from] UdevError),
#[error("Stat failed")]
Stat(#[source] OsError),
} }
pub struct LibInput { pub struct LibInput {
@ -59,20 +83,71 @@ pub struct LibInput {
} }
impl LibInput { impl LibInput {
pub fn new() -> Result<Self, LibInputError> { pub fn new(adapter: Rc<dyn LibInputAdapter>) -> Result<Self, LibInputError> {
let mut ud = Box::new(UserData {}); let mut ud = Box::new(UserData { adapter });
let li = unsafe { let li = unsafe {
libinput_path_create_context(&INTERFACE, &mut *ud as *mut _ as *mut c::c_void) libinput_path_create_context(&INTERFACE, &mut *ud as *mut _ as *mut c::c_void)
}; };
if li.is_null() { if li.is_null() {
return Err(LibInputError::New); return Err(LibInputError::New);
} }
unsafe {
libinput_log_set_handler(li, log_handler);
let priority = if log::log_enabled!(log::Level::Debug) {
LIBINPUT_LOG_PRIORITY_DEBUG
} else if log::log_enabled!(log::Level::Info) {
LIBINPUT_LOG_PRIORITY_INFO
} else {
LIBINPUT_LOG_PRIORITY_ERROR
};
libinput_log_set_priority(li, priority.raw() as _);
}
Ok(Self { data: ud, li }) Ok(Self { data: ud, li })
} }
pub fn fd(&self) -> c::c_int { pub fn fd(&self) -> c::c_int {
unsafe { libinput_get_fd(self.li) } unsafe { libinput_get_fd(self.li) }
} }
pub fn open<'a>(
self: &Rc<Self>,
path: impl IntoUstr<'a>,
) -> Result<RegisteredDevice, LibInputError> {
let path = path.into_ustr();
let res = unsafe { libinput_path_add_device(self.li, path.as_ptr()) };
if res.is_null() {
Err(LibInputError::Open)
} else {
unsafe {
libinput_device_ref(res);
}
Ok(RegisteredDevice {
li: self.clone(),
dev: res,
})
}
}
pub fn dispatch(&self) -> Result<(), LibInputError> {
let res = unsafe { libinput_dispatch(self.li) };
if res < 0 {
Err(LibInputError::Dispatch(Errno(-res).into()))
} else {
Ok(())
}
}
pub fn event(&self) -> Option<LibInputEvent> {
let res = unsafe { libinput_get_event(self.li) };
if res.is_null() {
None
} else {
Some(LibInputEvent {
event: res,
_phantom: Default::default(),
})
}
}
} }
impl Drop for LibInput { impl Drop for LibInput {
@ -82,3 +157,25 @@ impl Drop for LibInput {
} }
} }
} }
unsafe extern "C" fn log_handler(
_libinput: *mut libinput,
priority: libinput_log_priority,
format: *const c::c_char,
args: VaList,
) {
let str = match vasprintf_(format, args) {
Some(s) => s,
_ => {
log::error!("Could not format log message");
return;
}
};
let priority = match LogPriority(priority as _) {
LIBINPUT_LOG_PRIORITY_DEBUG => log::Level::Debug,
LIBINPUT_LOG_PRIORITY_INFO => log::Level::Info,
LIBINPUT_LOG_PRIORITY_ERROR => log::Level::Error,
_ => log::Level::Error,
};
log::log!(priority, "libinput: {}", str.to_bytes().trim().as_bstr());
}

152
src/libinput/consts.rs Normal file
View file

@ -0,0 +1,152 @@
#![allow(dead_code)]
cenum! {
LogPriority, LIBINPUT_LOG_PRIORITY;
LIBINPUT_LOG_PRIORITY_DEBUG = 10,
LIBINPUT_LOG_PRIORITY_INFO = 20,
LIBINPUT_LOG_PRIORITY_ERROR = 30,
}
cenum! {
DeviceCapability, LIBINPUT_DEVICE_CAPABILITY;
LIBINPUT_DEVICE_CAP_KEYBOARD = 0,
LIBINPUT_DEVICE_CAP_POINTER = 1,
LIBINPUT_DEVICE_CAP_TOUCH = 2,
LIBINPUT_DEVICE_CAP_TABLET_TOOL = 3,
LIBINPUT_DEVICE_CAP_TABLET_PAD = 4,
LIBINPUT_DEVICE_CAP_GESTURE = 5,
LIBINPUT_DEVICE_CAP_SWITCH = 6,
}
cenum! {
KeyState, LIBINPUT_KEY_STATE;
LIBINPUT_KEY_STATE_RELEASED = 0,
LIBINPUT_KEY_STATE_PRESSED = 1,
}
cenum! {
Led, LIBINPUT_LED;
LIBINPUT_LED_NUM_LOCK = 1 << 0,
LIBINPUT_LED_CAPS_LOCK = 1 << 1,
LIBINPUT_LED_SCROLL_LOCK = 1 << 2,
}
cenum! {
ButtonState, LIBINPUT_BUTTON_STATE;
LIBINPUT_BUTTON_STATE_RELEASED = 0,
LIBINPUT_BUTTON_STATE_PRESSED = 1,
}
cenum! {
PointerAxis, LIBINPUT_POINTER_AXIS;
LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL = 0,
LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL = 1,
}
cenum! {
PointerAxisSource, LIBINPUT_POINTER_AXIS_SOURCE;
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL = 1,
LIBINPUT_POINTER_AXIS_SOURCE_FINGER = 2,
LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS = 3,
LIBINPUT_POINTER_AXIS_SOURCE_WHEEL_TILT = 4,
}
cenum! {
TabletPadRingAxisSource, LIBINPUT_TABLET_PAD_RING_AXIS_SOURCE;
LIBINPUT_TABLET_PAD_RING_SOURCE_UNKNOWN = 1,
LIBINPUT_TABLET_PAD_RING_SOURCE_FINGER = 2,
}
cenum! {
TabletPadStripAxisSource, LIBINPUT_TABLET_PAD_STRIP_AXIS_SOURCE;
LIBINPUT_TABLET_PAD_STRIP_SOURCE_UNKNOWN = 1,
LIBINPUT_TABLET_PAD_STRIP_SOURCE_FINGER = 2,
}
cenum! {
TabletToolType, LIBINPUT_TABLET_TOOL_TYPE;
LIBINPUT_TABLET_TOOL_TYPE_PEN = 1,
LIBINPUT_TABLET_TOOL_TYPE_ERASER = 2,
LIBINPUT_TABLET_TOOL_TYPE_BRUSH = 3,
LIBINPUT_TABLET_TOOL_TYPE_PENCIL = 4,
LIBINPUT_TABLET_TOOL_TYPE_AIRBRUSH = 5,
LIBINPUT_TABLET_TOOL_TYPE_MOUSE = 6,
LIBINPUT_TABLET_TOOL_TYPE_LENS = 7,
LIBINPUT_TABLET_TOOL_TYPE_TOTEM = 8,
}
cenum! {
TabletToolProximityState, LIBINPUT_TABLET_TOOL_PROXIMITY_STATE;
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT = 0,
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN = 1,
}
cenum! {
TabletToolTipState, LIBINPUT_TABLET_TOOL_TIP_STATE;
LIBINPUT_TABLET_TOOL_TIP_UP = 0,
LIBINPUT_TABLET_TOOL_TIP_DOWN = 1,
}
cenum! {
SwitchState, LIBINPUT_SWITCH_STATE;
LIBINPUT_SWITCH_STATE_OFF = 0,
LIBINPUT_SWITCH_STATE_ON = 1,
}
cenum! {
Switch, LIBINPUT_SWITCH;
LIBINPUT_SWITCH_LID = 1,
LIBINPUT_SWITCH_TABLET_MODE = 2,
}
cenum! {
EventType, LIBINPUT_EVENT_TYPE;
LIBINPUT_EVENT_NONE = 0,
LIBINPUT_EVENT_DEVICE_ADDED = 1,
LIBINPUT_EVENT_DEVICE_REMOVED = 2,
LIBINPUT_EVENT_KEYBOARD_KEY = 300,
LIBINPUT_EVENT_POINTER_MOTION = 400,
LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE = 401,
LIBINPUT_EVENT_POINTER_BUTTON = 402,
LIBINPUT_EVENT_POINTER_AXIS = 403,
LIBINPUT_EVENT_POINTER_SCROLL_WHEEL = 404,
LIBINPUT_EVENT_POINTER_SCROLL_FINGER = 405,
LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS = 406,
LIBINPUT_EVENT_TOUCH_DOWN = 500,
LIBINPUT_EVENT_TOUCH_UP = 501,
LIBINPUT_EVENT_TOUCH_MOTION = 502,
LIBINPUT_EVENT_TOUCH_CANCEL = 503,
LIBINPUT_EVENT_TOUCH_FRAME = 504,
LIBINPUT_EVENT_TABLET_TOOL_AXIS = 600,
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY = 601,
LIBINPUT_EVENT_TABLET_TOOL_TIP = 602,
LIBINPUT_EVENT_TABLET_TOOL_BUTTON = 603,
LIBINPUT_EVENT_TABLET_PAD_BUTTON = 700,
LIBINPUT_EVENT_TABLET_PAD_RING = 701,
LIBINPUT_EVENT_TABLET_PAD_STRIP = 702,
LIBINPUT_EVENT_TABLET_PAD_KEY = 703,
LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN = 800,
LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE = 801,
LIBINPUT_EVENT_GESTURE_SWIPE_END = 802,
LIBINPUT_EVENT_GESTURE_PINCH_BEGIN = 803,
LIBINPUT_EVENT_GESTURE_PINCH_UPDATE = 804,
LIBINPUT_EVENT_GESTURE_PINCH_END = 805,
LIBINPUT_EVENT_GESTURE_HOLD_BEGIN = 806,
LIBINPUT_EVENT_GESTURE_HOLD_END = 807,
LIBINPUT_EVENT_SWITCH_TOGGLE = 900,
}

51
src/libinput/device.rs Normal file
View file

@ -0,0 +1,51 @@
use crate::libinput::sys::{
libinput_device, libinput_device_set_user_data, libinput_device_unref,
libinput_path_remove_device,
};
use crate::libinput::LibInput;
use std::marker::PhantomData;
use std::rc::Rc;
pub struct LibInputDevice<'a> {
pub(super) dev: *mut libinput_device,
pub(super) _phantom: PhantomData<&'a ()>,
}
pub struct RegisteredDevice {
pub(super) li: Rc<LibInput>,
pub(super) dev: *mut libinput_device,
}
impl<'a> LibInputDevice<'a> {
pub fn set_slot(&self, slot: usize) {
self.set_slot_(slot + 1)
}
pub fn unset_slot(&self) {
self.set_slot_(0)
}
fn set_slot_(&self, slot: usize) {
unsafe {
libinput_device_set_user_data(self.dev, slot as _);
}
}
}
impl RegisteredDevice {
pub fn device(&self) -> LibInputDevice {
LibInputDevice {
dev: self.dev,
_phantom: Default::default(),
}
}
}
impl Drop for RegisteredDevice {
fn drop(&mut self) {
unsafe {
libinput_path_remove_device(self.dev);
libinput_device_unref(self.dev);
}
}
}

66
src/libinput/event.rs Normal file
View file

@ -0,0 +1,66 @@
use crate::libinput::consts::{EventType, KeyState};
use crate::libinput::device::LibInputDevice;
use crate::libinput::sys::{
libinput_event, libinput_event_destroy, libinput_event_get_device,
libinput_event_get_keyboard_event, libinput_event_get_type, libinput_event_keyboard,
libinput_event_keyboard_get_key, libinput_event_keyboard_get_key_state,
libinput_event_keyboard_get_time_usec,
};
use std::marker::PhantomData;
pub struct LibInputEvent<'a> {
pub(super) event: *mut libinput_event,
pub(super) _phantom: PhantomData<&'a ()>,
}
pub struct LibInputEventKeyboard<'a> {
pub(super) event: *mut libinput_event_keyboard,
pub(super) _phantom: PhantomData<&'a ()>,
}
impl<'a> Drop for LibInputEvent<'a> {
fn drop(&mut self) {
unsafe {
libinput_event_destroy(self.event);
}
}
}
impl<'a> LibInputEvent<'a> {
pub fn ty(&self) -> EventType {
unsafe { EventType(libinput_event_get_type(self.event)) }
}
pub fn device(&self) -> LibInputDevice {
LibInputDevice {
dev: unsafe { libinput_event_get_device(self.event) },
_phantom: Default::default(),
}
}
pub fn keyboard_event(&self) -> Option<LibInputEventKeyboard> {
let res = unsafe { libinput_event_get_keyboard_event(self.event) };
if res.is_null() {
None
} else {
Some(LibInputEventKeyboard {
event: res,
_phantom: Default::default(),
})
}
}
}
impl<'a> LibInputEventKeyboard<'a> {
pub fn key(&self) -> u32 {
unsafe { libinput_event_keyboard_get_key(self.event) }
}
pub fn key_state(&self) -> KeyState {
unsafe { KeyState(libinput_event_keyboard_get_key_state(self.event)) }
}
pub fn time_usec(&self) -> u64 {
unsafe { libinput_event_keyboard_get_time_usec(self.event) }
}
}

64
src/libinput/sys.rs Normal file
View file

@ -0,0 +1,64 @@
use std::ffi::VaList;
use uapi::c;
include!(concat!(env!("OUT_DIR"), "/libinput_tys.rs"));
pub type libinput_log_handler = unsafe extern "C" fn(
libinput: *mut libinput,
priority: libinput_log_priority,
format: *const c::c_char,
args: VaList,
);
#[link(name = "input")]
extern "C" {
pub type libinput;
pub type libinput_device;
pub type libinput_event;
pub type libinput_event_keyboard;
pub fn libinput_log_set_handler(libinput: *mut libinput, log_handler: libinput_log_handler);
pub fn libinput_log_set_priority(libinput: *mut libinput, priority: libinput_log_priority);
pub fn libinput_path_create_context(
interface: *const libinput_interface,
user_data: *mut c::c_void,
) -> *mut libinput;
pub fn libinput_device_set_user_data(device: *mut libinput_device, user_data: *mut c::c_void);
pub fn libinput_device_get_user_data(device: *mut libinput_device) -> *mut c::c_void;
pub fn libinput_device_ref(device: *mut libinput_device) -> *mut libinput_device;
pub fn libinput_device_unref(device: *mut libinput_device) -> *mut libinput_device;
pub fn libinput_path_add_device(
libinput: *mut libinput,
path: *const c::c_char,
) -> *mut libinput_device;
pub fn libinput_path_remove_device(device: *mut libinput_device);
pub fn libinput_unref(libinput: *mut libinput) -> *mut libinput;
pub fn libinput_get_fd(libinput: *mut libinput) -> c::c_int;
pub fn libinput_dispatch(libinput: *mut libinput) -> c::c_int;
pub fn libinput_get_event(libinput: *mut libinput) -> *mut libinput_event;
pub fn libinput_event_destroy(event: *mut libinput_event);
pub fn libinput_event_get_type(event: *mut libinput_event) -> libinput_event_type;
pub fn libinput_event_get_device(event: *mut libinput_event) -> *mut libinput_device;
pub fn libinput_event_get_keyboard_event(
event: *mut libinput_event,
) -> *mut libinput_event_keyboard;
pub fn libinput_event_keyboard_get_key(event: *mut libinput_event_keyboard) -> u32;
pub fn libinput_event_keyboard_get_key_state(
event: *mut libinput_event_keyboard,
) -> libinput_key_state;
pub fn libinput_event_keyboard_get_time_usec(event: *mut libinput_event_keyboard) -> u64;
}
#[repr(C)]
pub struct libinput_interface {
pub open_restricted: unsafe extern "C" fn(
path: *const c::c_char,
flags: c::c_int,
user_data: *mut c::c_void,
) -> c::c_int,
pub close_restricted: unsafe extern "C" fn(fd: c::c_int, user_data: *mut c::c_void),
}

View file

@ -1,8 +1,9 @@
use crate::dbus::{DbusError, DbusSocket, Reply}; use crate::dbus::{DbusError, DbusSocket};
use crate::org::freedesktop::login1::session::TakeControlReply; use crate::org::freedesktop::login1::session::TakeDeviceReply;
use crate::{org, FALSE}; use crate::{org, FALSE};
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use uapi::c;
const LOGIND_NAME: &str = "org.freedesktop.login1"; const LOGIND_NAME: &str = "org.freedesktop.login1";
const MANAGER_PATH: &str = "/org/freedesktop/login1"; const MANAGER_PATH: &str = "/org/freedesktop/login1";
@ -72,8 +73,22 @@ impl Session {
) )
.await; .await;
match res { match res {
Ok(r) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(LogindError::TakeControl(e)), Err(e) => Err(LogindError::TakeControl(e)),
} }
} }
pub fn get_device<F>(&self, dev: c::dev_t, f: F)
where
F: FnOnce(Result<&TakeDeviceReply, DbusError>) + 'static,
{
let major = uapi::major(dev) as _;
let minor = uapi::minor(dev) as _;
self.socket.call(
LOGIND_NAME,
&self.session_path,
org::freedesktop::login1::session::TakeDevice { major, minor },
move |r| f(r),
);
}
} }

View file

@ -330,6 +330,7 @@ macro_rules! assert_size_eq {
}}; }};
} }
#[allow(unused_macros)]
macro_rules! assert_size_le { macro_rules! assert_size_le {
($t:ty, $u:ty) => {{ ($t:ty, $u:ty) => {{
struct AssertLeSize<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>); struct AssertLeSize<T, U>(std::marker::PhantomData<T>, std::marker::PhantomData<U>);

View file

@ -17,10 +17,11 @@
use crate::acceptor::AcceptorError; use crate::acceptor::AcceptorError;
use crate::async_engine::{AsyncError, Phase}; use crate::async_engine::{AsyncError, Phase};
use crate::backends::dummy::DummyBackend; use crate::backends::dummy::DummyBackend;
use crate::backends::xorg::{XorgBackend, XorgBackendError}; use crate::backends::metal;
use crate::backends::xorg::XorgBackendError;
use crate::client::Clients; use crate::client::Clients;
use crate::clientmem::ClientMemError; use crate::clientmem::ClientMemError;
use crate::dbus::{Dbus, FALSE, TRUE}; use crate::dbus::{Dbus, FALSE};
use crate::event_loop::EventLoopError; use crate::event_loop::EventLoopError;
use crate::forker::ForkerError; use crate::forker::ForkerError;
use crate::globals::Globals; use crate::globals::Globals;
@ -55,7 +56,6 @@ use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use wheel::Wheel; use wheel::Wheel;
use crate::backends::metal;
#[macro_use] #[macro_use]
mod macros; mod macros;

View file

@ -10,15 +10,15 @@ use uapi::{c, Errno, OwnedFd};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ServerMemError { pub enum ServerMemError {
#[error("memfd_create failed")] #[error("memfd_create failed")]
MemfdCreate(#[source] std::io::Error), MemfdCreate(#[source] crate::utils::oserror::OsError),
#[error("The provided size does not fit into off_t")] #[error("The provided size does not fit into off_t")]
SizeOverflow, SizeOverflow,
#[error("ftruncate failed")] #[error("ftruncate failed")]
Ftruncate(#[source] std::io::Error), Ftruncate(#[source] crate::utils::oserror::OsError),
#[error("mmap failed")] #[error("mmap failed")]
MmapFailed(#[source] std::io::Error), MmapFailed(#[source] crate::utils::oserror::OsError),
#[error("sealing failed")] #[error("sealing failed")]
Seal(#[source] std::io::Error), Seal(#[source] crate::utils::oserror::OsError),
} }
pub struct ServerMem { pub struct ServerMem {

View file

@ -10,11 +10,11 @@ pub enum SighandError {
#[error("The signal fd is in an error state")] #[error("The signal fd is in an error state")]
ErrorEvent, ErrorEvent,
#[error("Could not read from the signal fd")] #[error("Could not read from the signal fd")]
ReadFailed(#[source] std::io::Error), ReadFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not block the signalfd signals")] #[error("Could not block the signalfd signals")]
BlockFailed(#[source] std::io::Error), BlockFailed(#[source] crate::utils::oserror::OsError),
#[error("Could not create a signalfd")] #[error("Could not create a signalfd")]
CreateFailed(#[source] std::io::Error), CreateFailed(#[source] crate::utils::oserror::OsError),
#[error("The event loop caused an error")] #[error("The event loop caused an error")]
EventLoopError(#[from] EventLoopError), EventLoopError(#[from] EventLoopError),
} }

View file

@ -8,7 +8,7 @@ use uapi::c;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum TimeError { pub enum TimeError {
#[error("clock_gettime failed: {0}")] #[error("clock_gettime failed: {0}")]
ClockGettime(std::io::Error), ClockGettime(crate::utils::oserror::OsError),
} }
#[derive(Copy, Clone)] #[derive(Copy, Clone)]

View file

@ -1,10 +1,9 @@
use crate::dbus::DbusError;
use std::ffi::CStr; use std::ffi::CStr;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr; use std::ptr;
use std::rc::Rc; use std::rc::Rc;
use thiserror::Error; use thiserror::Error;
use uapi::{c, Errno, IntoUstr, Ustr}; use uapi::{c, Errno, IntoUstr};
#[link(name = "udev")] #[link(name = "udev")]
extern "C" { extern "C" {
@ -47,32 +46,33 @@ extern "C" {
fn udev_device_get_sysname(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_sysname(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_is_initialized(udev_device: *mut udev_device) -> c::c_int; fn udev_device_get_is_initialized(udev_device: *mut udev_device) -> c::c_int;
fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c::c_char; fn udev_device_get_devnode(udev_device: *mut udev_device) -> *const c::c_char;
fn udev_device_get_devnum(udev_device: *mut udev_device) -> c::dev_t;
} }
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum UdevError { pub enum UdevError {
#[error("Could not create a new udev instance")] #[error("Could not create a new udev instance")]
New(#[source] std::io::Error), New(#[source] crate::utils::oserror::OsError),
#[error("Could not create a new udev_monitor instance")] #[error("Could not create a new udev_monitor instance")]
NewMonitor(#[source] std::io::Error), NewMonitor(#[source] crate::utils::oserror::OsError),
#[error("Could not create a new udev_enumerate instance")] #[error("Could not create a new udev_enumerate instance")]
NewEnumerate(#[source] std::io::Error), NewEnumerate(#[source] crate::utils::oserror::OsError),
#[error("Could not enable receiving on a udev_monitor")] #[error("Could not enable receiving on a udev_monitor")]
EnableReceiving(#[source] std::io::Error), EnableReceiving(#[source] crate::utils::oserror::OsError),
#[error("Could not add a match rule to a udev_monitor")] #[error("Could not add a match rule to a udev_monitor")]
MonitorAddMatch(#[source] std::io::Error), MonitorAddMatch(#[source] crate::utils::oserror::OsError),
#[error("Could not add a match rule to a udev_enumerate")] #[error("Could not add a match rule to a udev_enumerate")]
EnumerateAddMatch(#[source] std::io::Error), EnumerateAddMatch(#[source] crate::utils::oserror::OsError),
#[error("Could not list devices of a udev_enumerate")] #[error("Could not list devices of a udev_enumerate")]
EnumerateGetListEntry(#[source] std::io::Error), EnumerateGetListEntry(#[source] crate::utils::oserror::OsError),
#[error("Could not scan devices of a udev_enumerate")] #[error("Could not scan devices of a udev_enumerate")]
ScanDevices(#[source] std::io::Error), ScanDevices(#[source] crate::utils::oserror::OsError),
#[error("Could not create a udev_device from a syspath")] #[error("Could not create a udev_device from a syspath")]
DeviceFromSyspath(#[source] std::io::Error), DeviceFromSyspath(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the sysname of a udev_device")] #[error("Could not retrieve the sysname of a udev_device")]
GetSysname(#[source] std::io::Error), GetSysname(#[source] crate::utils::oserror::OsError),
#[error("Could not retrieve the devnode of a udev_device")] #[error("Could not retrieve the devnode of a udev_device")]
GetDevnode(#[source] std::io::Error), GetDevnode(#[source] crate::utils::oserror::OsError),
} }
pub struct Udev { pub struct Udev {
@ -193,9 +193,7 @@ impl UdevMonitor {
} }
pub fn receive_device(&self) -> Option<UdevDevice> { pub fn receive_device(&self) -> Option<UdevDevice> {
let res = unsafe { let res = unsafe { udev_monitor_receive_device(self.monitor) };
udev_monitor_receive_device(self.monitor)
};
if res.is_null() { if res.is_null() {
None None
} else { } else {
@ -303,6 +301,10 @@ impl UdevDevice {
} }
} }
pub fn devnum(&self) -> c::dev_t {
unsafe { udev_device_get_devnum(self.device) }
}
pub fn is_initialized(&self) -> bool { pub fn is_initialized(&self) -> bool {
unsafe { udev_device_get_is_initialized(self.device) != 0 } unsafe { udev_device_get_is_initialized(self.device) != 0 }
} }

View file

@ -13,7 +13,7 @@ mod parser;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum BufFdError { pub enum BufFdError {
#[error("An IO error occurred")] #[error("An IO error occurred")]
Io(#[source] std::io::Error), Io(#[source] crate::utils::oserror::OsError),
#[error("An async error occurred")] #[error("An async error occurred")]
Async(#[from] AsyncError), Async(#[from] AsyncError),
#[error("The peer did not send a file descriptor")] #[error("The peer did not send a file descriptor")]

View file

@ -1,5 +1,6 @@
pub mod array; pub mod array;
pub mod asyncevent; pub mod asyncevent;
pub mod bitfield;
pub mod bitflags; pub mod bitflags;
pub mod buffd; pub mod buffd;
pub mod clonecell; pub mod clonecell;
@ -9,12 +10,13 @@ pub mod errorfmt;
pub mod hex; pub mod hex;
pub mod linkedlist; pub mod linkedlist;
pub mod numcell; pub mod numcell;
pub mod oserror;
pub mod ptr_ext; pub mod ptr_ext;
pub mod queue; pub mod queue;
pub mod run_toplevel; pub mod run_toplevel;
pub mod smallmap; pub mod smallmap;
pub mod stack; pub mod stack;
pub mod tri; pub mod tri;
pub mod vasprintf;
pub mod vec_ext; pub mod vec_ext;
pub mod vecstorage; pub mod vecstorage;
pub mod bitfield;

181
src/utils/oserror.rs Normal file
View file

@ -0,0 +1,181 @@
use once_cell::sync::Lazy;
use std::error::Error;
use std::fmt::{Display, Formatter};
use uapi::{c, Errno};
static ERRORS: Lazy<&'static [Option<&'static str>]> = Lazy::new(|| {
static MSGS: &'static [(c::c_int, &'static str)] = &[
(c::EWOULDBLOCK, "Operation would block"),
(c::ENOTSUP, "Not supported"),
(c::EHWPOISON, "Memory page has hardware error"),
(c::ERFKILL, "Operation not possible due to RF-kill"),
(c::EKEYREJECTED, "Key was rejected by service"),
(c::EKEYREVOKED, "Key has been revoked"),
(c::EKEYEXPIRED, "Key has expired"),
(c::ENOKEY, "Required key not available"),
(c::EMEDIUMTYPE, "Wrong medium type"),
(c::ENOMEDIUM, "No medium found"),
(c::EREMOTEIO, "Remote I/O error"),
(c::EISNAM, "Is a named type file"),
(c::ENAVAIL, "No XENIX semaphores available"),
(c::ENOTNAM, "Not a XENIX named type file"),
(c::EUCLEAN, "Structure needs cleaning"),
(c::ESTRPIPE, "Streams pipe error"),
(c::ELIBEXEC, "Cannot exec a shared library directly"),
(
c::ELIBMAX,
"Attempting to link in too many shared libraries",
),
(c::ELIBSCN, ".lib section in a.out corrupted"),
(c::ELIBBAD, "Accessing a corrupted shared library"),
(c::ELIBACC, "Can not access a needed shared library"),
(c::EREMCHG, "Remote address changed"),
(c::EBADFD, "File descriptor in bad state"),
(c::ENOTUNIQ, "Name not unique on network"),
(c::EDOTDOT, "RFS specific error"),
(c::ECOMM, "Communication error on send"),
(c::ESRMNT, "Srmount error"),
(c::EADV, "Advertise error"),
(c::ENOPKG, "Package not installed"),
(c::ENONET, "Machine is not on the network"),
(c::EBFONT, "Bad font file format"),
(c::EBADSLT, "Invalid slot"),
(c::EBADRQC, "Invalid request code"),
(c::ENOANO, "No anode"),
(c::EXFULL, "Exchange full"),
(c::EBADR, "Invalid request descriptor"),
(c::EBADE, "Invalid exchange"),
(c::EL2HLT, "Level 2 halted"),
(c::ENOCSI, "No CSI structure available"),
(c::EUNATCH, "Protocol driver not attached"),
(c::ELNRNG, "Link number out of range"),
(c::EL3RST, "Level 3 reset"),
(c::EL3HLT, "Level 3 halted"),
(c::EL2NSYNC, "Level 2 not synchronized"),
(c::ECHRNG, "Channel number out of range"),
(c::ERESTART, "Interrupted system call should be restarted"),
(c::ENOTRECOVERABLE, "State not recoverable"),
(c::EOWNERDEAD, "Owner died"),
(c::ECANCELED, "Operation canceled"),
(c::ETIME, "Timer expired"),
(c::EPROTO, "Protocol error"),
(c::EOVERFLOW, "Value too large for defined data type"),
(c::ENOSTR, "Device not a stream"),
(c::ENOSR, "Out of streams resources"),
(c::ENOMSG, "No message of desired type"),
(c::ENOLINK, "Link has been severed"),
(c::ENODATA, "No data available"),
(c::EMULTIHOP, "Multihop attempted"),
(c::EIDRM, "Identifier removed"),
(c::EBADMSG, "Bad message"),
(
c::EILSEQ,
"Invalid or incomplete multibyte or wide character",
),
(c::ENOSYS, "Function not implemented"),
(c::ENOLCK, "No locks available"),
(c::EREMOTE, "Object is remote"),
(c::ESTALE, "Stale file handle"),
(c::EDQUOT, "Disk quota exceeded"),
(c::EUSERS, "Too many users"),
(c::ENOTEMPTY, "Directory not empty"),
(c::EHOSTUNREACH, "No route to host"),
(c::EHOSTDOWN, "Host is down"),
(c::ENAMETOOLONG, "File name too long"),
(c::ELOOP, "Too many levels of symbolic links"),
(c::ECONNREFUSED, "Connection refused"),
(c::ETIMEDOUT, "Connection timed out"),
(c::ETOOMANYREFS, "Too many references: cannot splice"),
(
c::ESHUTDOWN,
"Cannot send after transport endpoint shutdown",
),
(c::EDESTADDRREQ, "Destination address required"),
(c::ENOTCONN, "Transport endpoint is not connected"),
(c::EISCONN, "Transport endpoint is already connected"),
(c::ENOBUFS, "No buffer space available"),
(c::ECONNRESET, "Connection reset by peer"),
(c::ECONNABORTED, "Software caused connection abort"),
(c::ENETRESET, "Network dropped connection on reset"),
(c::ENETUNREACH, "Network is unreachable"),
(c::ENETDOWN, "Network is down"),
(c::EADDRNOTAVAIL, "Cannot assign requested address"),
(c::EADDRINUSE, "Address already in use"),
(c::EAFNOSUPPORT, "Address family not supported by protocol"),
(c::EPFNOSUPPORT, "Protocol family not supported"),
(c::EOPNOTSUPP, "Operation not supported"),
(c::ESOCKTNOSUPPORT, "Socket type not supported"),
(c::EPROTONOSUPPORT, "Protocol not supported"),
(c::ENOPROTOOPT, "Protocol not available"),
(c::EPROTOTYPE, "Protocol wrong type for socket"),
(c::EMSGSIZE, "Message too long"),
(c::ENOTSOCK, "Socket operation on non-socket"),
(c::EALREADY, "Operation already in progress"),
(c::EINPROGRESS, "Operation now in progress"),
(c::EAGAIN, "Resource temporarily unavailable"),
(c::ERANGE, "Numerical result out of range"),
(c::EDOM, "Numerical argument out of domain"),
(c::EPIPE, "Broken pipe"),
(c::EMLINK, "Too many links"),
(c::EROFS, "Read-only file system"),
(c::ESPIPE, "Illegal seek"),
(c::ENOSPC, "No space left on device"),
(c::EFBIG, "File too large"),
(c::ETXTBSY, "Text file busy"),
(c::ENOTTY, "Inappropriate ioctl for device"),
(c::ENFILE, "Too many open files in system"),
(c::EMFILE, "Too many open files"),
(c::EINVAL, "Invalid argument"),
(c::EISDIR, "Is a directory"),
(c::ENOTDIR, "Not a directory"),
(c::ENODEV, "No such device"),
(c::EXDEV, "Invalid cross-device link"),
(c::EEXIST, "File exists"),
(c::EBUSY, "Device or resource busy"),
(c::ENOTBLK, "Block device required"),
(c::EFAULT, "Bad address"),
(c::EACCES, "Permission denied"),
(c::ENOMEM, "Cannot allocate memory"),
(c::EDEADLK, "Resource deadlock avoided"),
(c::ECHILD, "No child processes"),
(c::EBADF, "Bad file descriptor"),
(c::ENOEXEC, "Exec format error"),
(c::E2BIG, "Argument list too long"),
(c::ENXIO, "No such device or address"),
(c::EIO, "Input/output error"),
(c::EINTR, "Interrupted system call"),
(c::ESRCH, "No such process"),
(c::ENOENT, "No such file or directory"),
(c::EPERM, "Operation not permitted"),
];
let mut res = vec![];
for &(idx, msg) in MSGS {
let idx = idx as usize;
while res.len() <= idx {
res.push(None);
}
res[idx] = Some(msg);
}
res.leak()
});
#[derive(Debug)]
pub struct OsError(pub c::c_int);
impl From<Errno> for OsError {
fn from(e: Errno) -> Self {
Self(e.0)
}
}
impl Error for OsError {}
impl Display for OsError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let msg = ERRORS
.get(self.0 as usize)
.and_then(|v| *v)
.unwrap_or("unknown error");
write!(f, "{} (os error {})", msg, self.0)
}
}

38
src/utils/vasprintf.rs Normal file
View file

@ -0,0 +1,38 @@
use std::ffi::{CStr, VaList};
use std::ops::Deref;
use std::ptr;
use uapi::c;
extern "C" {
fn vasprintf(strp: *mut *mut c::c_char, fmt: *const c::c_char, ap: VaList) -> c::c_int;
}
pub struct OwnedCStr {
val: &'static CStr,
}
impl Deref for OwnedCStr {
type Target = CStr;
fn deref(&self) -> &Self::Target {
self.val
}
}
impl Drop for OwnedCStr {
fn drop(&mut self) {
unsafe {
c::free(self.val.as_ptr() as _);
}
}
}
pub unsafe fn vasprintf_(fmt: *const c::c_char, ap: VaList) -> Option<OwnedCStr> {
let mut res = ptr::null_mut();
if vasprintf(&mut res, fmt, ap) == -1 {
return None;
}
Some(OwnedCStr {
val: CStr::from_ptr(res),
})
}

View file

@ -14,9 +14,9 @@ use uapi::{c, OwnedFd};
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum WheelError { pub enum WheelError {
#[error("Could not create the timerfd: {0}")] #[error("Could not create the timerfd: {0}")]
CreateFailed(std::io::Error), CreateFailed(crate::utils::oserror::OsError),
#[error("Could not set the timerfd: {0}")] #[error("Could not set the timerfd: {0}")]
SetFailed(std::io::Error), SetFailed(crate::utils::oserror::OsError),
#[error("The timerfd is in an error state")] #[error("The timerfd is in an error state")]
ErrorEvent, ErrorEvent,
#[error("An event loop error occurred: {0}")] #[error("An event loop error occurred: {0}")]

View file

@ -20,11 +20,11 @@ use uapi::{c, pipe2, Errno, OwnedFd};
#[derive(Debug, Error)] #[derive(Debug, Error)]
enum XWaylandError { enum XWaylandError {
#[error("Could not create a wayland socket")] #[error("Could not create a wayland socket")]
SocketFailed(#[source] std::io::Error), SocketFailed(#[source] crate::utils::oserror::OsError),
#[error("/tmp/.X11-unix does not exist")] #[error("/tmp/.X11-unix does not exist")]
MissingSocketDir, MissingSocketDir,
#[error("Could not stat /tmp/.X11-unix")] #[error("Could not stat /tmp/.X11-unix")]
StatSocketDir(#[source] std::io::Error), StatSocketDir(#[source] crate::utils::oserror::OsError),
#[error("/tmp/.X11-unix is not a directory")] #[error("/tmp/.X11-unix is not a directory")]
NotASocketDir, NotASocketDir,
#[error("/tmp/.X11-unix is writable")] #[error("/tmp/.X11-unix is writable")]
@ -38,17 +38,17 @@ enum XWaylandError {
#[error("The socket is already in use")] #[error("The socket is already in use")]
AlreadyInUse, AlreadyInUse,
#[error("Could not bind the socket to an address")] #[error("Could not bind the socket to an address")]
BindFailed(#[source] std::io::Error), BindFailed(#[source] crate::utils::oserror::OsError),
#[error("All X displays in the range 0..1000 are already in use")] #[error("All X displays in the range 0..1000 are already in use")]
AddressesInUse, AddressesInUse,
#[error("The async engine returned an error")] #[error("The async engine returned an error")]
AsyncError(#[from] AsyncError), AsyncError(#[from] AsyncError),
#[error("pipe(2) failed")] #[error("pipe(2) failed")]
Pipe(#[source] std::io::Error), Pipe(#[source] crate::utils::oserror::OsError),
#[error("dupfd(2) failed")] #[error("dupfd(2) failed")]
Dupfd(#[source] std::io::Error), Dupfd(#[source] crate::utils::oserror::OsError),
#[error("socketpair(2) failed")] #[error("socketpair(2) failed")]
Socketpair(#[source] std::io::Error), Socketpair(#[source] crate::utils::oserror::OsError),
#[error("Could not start Xwayland")] #[error("Could not start Xwayland")]
ExecFailed(#[source] ForkerError), ExecFailed(#[source] ForkerError),
#[error("Could not load the atoms")] #[error("Could not load the atoms")]
@ -224,7 +224,10 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
let mut done = false; let mut done = false;
while !done { while !done {
if let Err(e) = afd.readable().await { if let Err(e) = afd.readable().await {
log::error!("Cannot wait for the xwayland stderr to become readable: {}", ErrorFmt(e)); log::error!(
"Cannot wait for the xwayland stderr to become readable: {}",
ErrorFmt(e)
);
return; return;
} }
loop { loop {
@ -242,7 +245,7 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
Err(e) => { Err(e) => {
log::error!( log::error!(
"Could not read from stderr fd: {}", "Could not read from stderr fd: {}",
ErrorFmt(std::io::Error::from(e)) ErrorFmt(crate::utils::oserror::OsError::from(e))
); );
return; return;
} }