From cacd49d15ac974030c6e7fd650ac42e0c669ae2c Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 15 Feb 2022 22:53:12 +0100 Subject: [PATCH] autocommit 2022-02-15 22:53:12 CET --- Cargo.lock | 99 ++++- Cargo.toml | 3 +- default-config/src/lib.rs | 14 +- i4config/src/_private/client.rs | 67 ++-- i4config/src/_private/ipc.rs | 44 ++- i4config/src/keyboard/mod.rs | 2 +- i4config/src/lib.rs | 33 +- src/acceptor.rs | 6 +- src/backends/xorg.rs | 5 +- src/config.rs | 20 +- src/config/handler.rs | 186 ++++++---- src/forker.rs | 344 ++++++++++++++++++ src/forker/clone3.rs | 56 +++ src/ifs/wl_seat.rs | 26 +- src/ifs/wl_seat/event_handling.rs | 4 +- src/ifs/wl_seat/wl_keyboard.rs | 2 +- src/ifs/wl_surface.rs | 4 +- src/ifs/wl_surface/xdg_surface.rs | 2 +- .../wl_surface/xdg_surface/xdg_toplevel.rs | 2 +- src/main.rs | 12 +- src/state.rs | 12 +- src/tasks/backend.rs | 2 +- src/tasks/device.rs | 32 +- src/tasks/mod.rs | 2 +- src/tree/container.rs | 23 +- src/tree/mod.rs | 9 +- src/utils/buffd/buf_out.rs | 55 ++- src/utils/copyhashmap.rs | 7 +- src/utils/linkedlist.rs | 3 +- src/utils/mod.rs | 2 +- src/utils/queue.rs | 6 + src/utils/stack.rs | 6 +- src/xkbcommon/mod.rs | 14 +- 33 files changed, 884 insertions(+), 220 deletions(-) create mode 100644 src/forker.rs create mode 100644 src/forker/clone3.rs diff --git a/Cargo.lock b/Cargo.lock index 02cf30c5..9bb93b60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -320,6 +320,7 @@ dependencies = [ "num-derive", "num-traits", "once_cell", + "parking_lot", "rand", "renderdoc", "repc", @@ -366,6 +367,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "lock_api" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -436,6 +446,29 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "pin-project-lite" version = "0.2.8" @@ -512,6 +545,15 @@ dependencies = [ "rand_core", ] +[[package]] +name = "redox_syscall" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.5.4" @@ -577,6 +619,12 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "slab" version = "0.4.5" @@ -642,9 +690,9 @@ dependencies = [ [[package]] name = "uapi" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c72d8c426678584cd311d3b8e9538778fd7d024de641b440850e458d50621fd" +checksum = "ea2a608d845b3ddcf7769250f94124d29e346c0f8fdb935756c6b758ac5d9b59" dependencies = [ "cc", "cfg-if 0.1.10", @@ -654,9 +702,9 @@ dependencies = [ [[package]] name = "uapi-proc" -version = "0.0.3" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16121f38f4afe754d6726ed388f1fb3e669c4594a3d29e1bdab1e795a450921f" +checksum = "54de46f980cea7b2ae8d8f7f9f1c35cf7062c68343e99345ef73758f8e60975a" dependencies = [ "lazy_static", "libc", @@ -721,6 +769,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "wio" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index 0279ccc5..09d18399 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,8 @@ panic = "abort" codegen-units = 1 [dependencies] -uapi = "0.2.4" +uapi = "0.2.7" +parking_lot = "0.12.0" thiserror = "1.0.30" ahash = "0.7.6" log = "0.4.14" diff --git a/default-config/src/lib.rs b/default-config/src/lib.rs index 524a0859..150a7811 100644 --- a/default-config/src/lib.rs +++ b/default-config/src/lib.rs @@ -1,7 +1,7 @@ -use i4config::keyboard::mods::{ALT, CTRL, Modifiers, SHIFT}; -use i4config::keyboard::syms::{SYM_Super_L, SYM_h, SYM_j, SYM_k, SYM_l, SYM_plus, SYM_minus, SYM_r, SYM_t}; +use i4config::keyboard::mods::{Modifiers, ALT, CTRL, SHIFT}; +use i4config::keyboard::syms::{SYM_Super_L, SYM_h, SYM_j, SYM_k, SYM_l, SYM_r, SYM_t, SYM_x}; use i4config::Direction::{Down, Left, Right, Up}; -use i4config::{config, shell, Seat, create_seat, input_devices, on_new_input_device}; +use i4config::{config, create_seat, input_devices, on_new_input_device, Seat, Command}; const MOD: Modifiers = ALT; @@ -15,8 +15,8 @@ fn configure_seat(s: Seat) { s.set_repeat_rate(new_rate, new_delay); }; - s.bind(CTRL | SYM_l, move || change_rate(-1)); - s.bind(CTRL | SYM_r, move || change_rate(1)); + s.bind(CTRL | SHIFT | SYM_l, move || change_rate(-1)); + s.bind(CTRL | SHIFT | SYM_r, move || change_rate(1)); s.bind(CTRL | SYM_h, move || s.focus(Left)); s.bind(CTRL | SYM_j, move || s.focus(Down)); @@ -32,7 +32,9 @@ fn configure_seat(s: Seat) { s.bind(MOD | SHIFT | SYM_k, move || s.move_(Up)); s.bind(MOD | SHIFT | SYM_l, move || s.move_(Right)); - s.bind(SYM_Super_L, || shell("alacritty")); + s.bind(SYM_x, || { + Command::new("alacritty").spawn() + }); } pub fn configure() { diff --git a/i4config/src/_private/client.rs b/i4config/src/_private/client.rs index db8cea35..661bede0 100644 --- a/i4config/src/_private/client.rs +++ b/i4config/src/_private/client.rs @@ -1,13 +1,13 @@ -use crate::_private::ipc::{InitMessage, Request, Response}; +use crate::_private::ipc::{ClientMessage, InitMessage, Response, ServerMessage}; use crate::_private::{bincode_ops, logging, Config, ConfigEntry, ConfigEntryGen, VERSION}; -use crate::{Axis, Direction, InputDevice, LogLevel, ModifiedKeySym, Seat}; +use crate::keyboard::keymap::Keymap; +use crate::{Axis, Command, Direction, InputDevice, LogLevel, ModifiedKeySym, Seat}; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::collections::HashMap; use std::ops::Deref; use std::rc::Rc; use std::{ptr, slice}; -use crate::keyboard::keymap::Keymap; pub(crate) struct Client { configure: extern "C" fn(), @@ -117,7 +117,7 @@ pub unsafe extern "C" fn handle_msg(data: *const u8, msg: *const u8, size: usize } impl Client { - fn send(&self, msg: &Request) { + fn send(&self, msg: &ClientMessage) { let mut buf = self.bufs.borrow_mut().pop().unwrap_or_default(); buf.clear(); bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap(); @@ -127,16 +127,21 @@ impl Client { self.bufs.borrow_mut().push(buf); } - pub fn shell(&self, shell: &str) { - self.send(&Request::Shell { script: shell }); + pub fn spawn(&self, command: &Command) { + let env = command.env.iter().map(|(a, b)| (a.to_string(), b.to_string())).collect(); + self.send(&ClientMessage::Run { + prog: &command.prog, + args: command.args.clone(), + env, + }); } pub fn focus(&self, seat: Seat, direction: Direction) { - self.send(&Request::Focus { seat, direction }); + self.send(&ClientMessage::Focus { seat, direction }); } pub fn move_(&self, seat: Seat, direction: Direction) { - self.send(&Request::Move { seat, direction }); + self.send(&ClientMessage::Move { seat, direction }); } pub fn unbind>(&self, seat: Seat, mod_sym: T) { @@ -147,7 +152,7 @@ impl Client { .remove(&(seat, mod_sym)) .is_some(); if deregister { - self.send(&Request::RemoveShortcut { + self.send(&ClientMessage::RemoveShortcut { seat, mods: mod_sym.mods, sym: mod_sym.sym, @@ -161,7 +166,7 @@ impl Client { } pub fn seats(&self) -> Vec { - let response = self.with_response(|| self.send(&Request::GetSeats)); + let response = self.with_response(|| self.send(&ClientMessage::GetSeats)); match response { Response::GetSeats { seats } => seats, _ => { @@ -172,22 +177,22 @@ impl Client { } pub fn split(&self, seat: Seat) -> Axis { - let res = self.with_response(|| self.send(&Request::GetSplit { seat })); + let res = self.with_response(|| self.send(&ClientMessage::GetSplit { seat })); match res { Response::GetSplit { axis } => axis, _ => { log::error!("Server did not send a response to a get_split request"); Axis::Horizontal - }, + } } } pub fn set_split(&self, seat: Seat, axis: Axis) { - self.send(&Request::SetSplit { seat, axis }); + self.send(&ClientMessage::SetSplit { seat, axis }); } pub fn create_seat(&self, name: &str) -> Seat { - let response = self.with_response(|| self.send(&Request::CreateSeat { name })); + let response = self.with_response(|| self.send(&ClientMessage::CreateSeat { name })); match response { Response::CreateSeat { seat } => seat, _ => { @@ -198,12 +203,12 @@ impl Client { } pub fn get_input_devices(&self) -> Vec { - let res = self.with_response(|| self.send(&Request::GetInputDevices)); + let res = self.with_response(|| self.send(&ClientMessage::GetInputDevices)); match res { Response::GetInputDevices { devices } => devices, _ => { log::error!("Server did not send a response to a get_input_devices request"); - vec!() + vec![] } } } @@ -217,19 +222,19 @@ impl Client { } pub fn set_seat(&self, device: InputDevice, seat: Seat) { - self.send(&Request::SetSeat { device, seat }) + self.send(&ClientMessage::SetSeat { device, seat }) } pub fn seat_set_keymap(&self, seat: Seat, keymap: Keymap) { - self.send(&Request::SeatSetKeymap { seat, keymap }) + self.send(&ClientMessage::SeatSetKeymap { seat, keymap }) } pub fn seat_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) { - self.send(&Request::SeatSetRepeatRate { seat, rate, delay }) + self.send(&ClientMessage::SeatSetRepeatRate { seat, rate, delay }) } pub fn seat_get_repeat_rate(&self, seat: Seat) -> (i32, i32) { - let res = self.with_response(|| self.send(&Request::SeatGetRepeatRate { seat })); + let res = self.with_response(|| self.send(&ClientMessage::SeatGetRepeatRate { seat })); match res { Response::GetRepeatRate { rate, delay } => (rate, delay), _ => { @@ -240,7 +245,7 @@ impl Client { } pub fn parse_keymap(&self, keymap: &str) -> Keymap { - let res = self.with_response(|| self.send(&Request::ParseKeymap { keymap })); + let res = self.with_response(|| self.send(&ClientMessage::ParseKeymap { keymap })); match res { Response::ParseKeymap { keymap } => keymap, _ => { @@ -267,7 +272,7 @@ impl Client { } }; if register { - self.send(&Request::AddShortcut { + self.send(&ClientMessage::AddShortcut { seat, mods: mod_sym.mods, sym: mod_sym.sym, @@ -276,7 +281,7 @@ impl Client { } pub fn log(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option) { - self.send(&Request::Log { + self.send(&ClientMessage::Log { level, msg, file, @@ -285,7 +290,7 @@ impl Client { } fn handle_msg(&self, msg: &[u8]) { - let res = bincode::decode_from_slice::(msg, bincode_ops()); + let res = bincode::decode_from_slice::(msg, bincode_ops()); let (msg, _) = match res { Ok(msg) => msg, Err(e) => { @@ -295,30 +300,26 @@ impl Client { } }; match msg { - Request::Configure => { + ServerMessage::Configure => { (self.configure)(); } - Request::Response { response } => { + ServerMessage::Response { response } => { self.response.borrow_mut().push(response); } - Request::InvokeShortcut { seat, mods, sym } => { + ServerMessage::InvokeShortcut { seat, mods, sym } => { let ms = ModifiedKeySym { mods, sym }; let handler = self.key_handlers.borrow_mut().get(&(seat, ms)).cloned(); if let Some(handler) = handler { handler(); } } - Request::NewInputDevice { device } => { + ServerMessage::NewInputDevice { device } => { let handler = self.on_new_input_device.borrow_mut().clone(); if let Some(handler) = handler { handler(device); } } - m => { - let err = format!("unexpected message: {:?}", m); - self.log(LogLevel::Error, &err, None, None); - return; - } + ServerMessage::DelInputDevice { .. } => {} } } diff --git a/i4config/src/_private/ipc.rs b/i4config/src/_private/ipc.rs index 81cf245f..82ed7f89 100644 --- a/i4config/src/_private/ipc.rs +++ b/i4config/src/_private/ipc.rs @@ -1,21 +1,36 @@ +use crate::keyboard::keymap::Keymap; use crate::keyboard::mods::Modifiers; use crate::keyboard::syms::KeySym; use crate::{Axis, Direction, InputDevice, LogLevel, Seat}; use bincode::{BorrowDecode, Decode, Encode}; -use crate::keyboard::keymap::Keymap; #[derive(Encode, BorrowDecode, Debug)] -pub enum Request<'a> { +pub enum ServerMessage { Configure, + Response { + response: Response, + }, + NewInputDevice { + device: InputDevice, + }, + DelInputDevice { + device: InputDevice, + }, + InvokeShortcut { + seat: Seat, + mods: Modifiers, + sym: KeySym, + }, +} + +#[derive(Encode, BorrowDecode, Debug)] +pub enum ClientMessage<'a> { Log { level: LogLevel, msg: &'a str, file: Option<&'a str>, line: Option, }, - Response { - response: Response, - }, CreateSeat { name: &'a str, }, @@ -50,12 +65,6 @@ pub enum Request<'a> { }, GetSeats, GetInputDevices, - NewInputDevice { - device: InputDevice, - }, - DelInputDevice { - device: InputDevice, - }, AddShortcut { seat: Seat, mods: Modifiers, @@ -66,13 +75,10 @@ pub enum Request<'a> { mods: Modifiers, sym: KeySym, }, - InvokeShortcut { - seat: Seat, - mods: Modifiers, - sym: KeySym, - }, - Shell { - script: &'a str, + Run { + prog: &'a str, + args: Vec, + env: Vec<(String, String)>, }, Focus { seat: Seat, @@ -90,7 +96,7 @@ pub enum Response { GetSeats { seats: Vec }, GetSplit { axis: Axis }, GetRepeatRate { rate: i32, delay: i32 }, - ParseKeymap { keymap: Keymap, }, + ParseKeymap { keymap: Keymap }, CreateSeat { seat: Seat }, GetInputDevices { devices: Vec }, } diff --git a/i4config/src/keyboard/mod.rs b/i4config/src/keyboard/mod.rs index bd614e54..43444161 100644 --- a/i4config/src/keyboard/mod.rs +++ b/i4config/src/keyboard/mod.rs @@ -3,9 +3,9 @@ use crate::keyboard::syms::KeySym; use bincode::{Decode, Encode}; use std::ops::{BitOr, BitOrAssign}; +pub mod keymap; pub mod mods; pub mod syms; -pub mod keymap; #[derive(Encode, Decode, Copy, Clone, Eq, PartialEq, Hash)] pub struct ModifiedKeySym { diff --git a/i4config/src/lib.rs b/i4config/src/lib.rs index 5415afdf..537f83bd 100644 --- a/i4config/src/lib.rs +++ b/i4config/src/lib.rs @@ -1,8 +1,9 @@ #![feature(thread_local_const_init)] +use std::collections::HashMap; +use crate::keyboard::keymap::Keymap; use crate::keyboard::ModifiedKeySym; use bincode::{Decode, Encode}; -use crate::keyboard::keymap::Keymap; #[macro_use] mod macros; @@ -151,6 +152,32 @@ pub fn on_new_input_device(f: F) { get!().on_new_input_device(f) } -pub fn shell(shell: &str) { - get!().shell(shell) +pub struct Command { + prog: String, + args: Vec, + env: HashMap, +} + +impl Command { + pub fn new(prog: &str) -> Self { + Self { + prog: prog.to_string(), + args: vec![], + env: Default::default(), + } + } + + pub fn arg(&mut self, arg: &str) -> &mut Self { + self.args.push(arg.to_string()); + self + } + + pub fn env(&mut self, key: &str, val: &str) -> &mut Self { + self.env.insert(key.to_string(), val.to_string()); + self + } + + pub fn spawn(&self) { + get!().spawn(self); + } } diff --git a/src/acceptor.rs b/src/acceptor.rs index bae366ce..8603465a 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -71,7 +71,7 @@ fn bind_socket(fd: i32, xdr: &str) -> Result { } impl Acceptor { - pub fn install(global: &Rc) -> Result<(), AcceptorError> { + pub fn install(global: &Rc) -> Result { let xrd = match std::env::var("XDG_RUNTIME_DIR") { Ok(d) => d, Err(_) => return Err(AcceptorError::XrdNotSet), @@ -87,7 +87,7 @@ impl Acceptor { let socket_id = bind_socket(fd.raw(), &xrd)?; let socket_path = socket_path(&xrd, socket_id); log::info!("bound to socket {}", socket_path); - let unlinker = Unlinker(socket_path); + let unlinker = Unlinker(socket_path.clone()); if let Err(e) = uapi::listen(fd.raw(), 4096) { return Err(AcceptorError::ListenFailed(e.into())); } @@ -99,7 +99,7 @@ impl Acceptor { global: global.clone(), }); global.el.insert(id, Some(acc.fd.raw()), c::EPOLLIN, acc)?; - Ok(()) + Ok(socket_path) } } diff --git a/src/backends/xorg.rs b/src/backends/xorg.rs index 2eafc807..f69cc701 100644 --- a/src/backends/xorg.rs +++ b/src/backends/xorg.rs @@ -1,4 +1,7 @@ -use crate::backend::{BackendEvent, Keyboard, KeyboardEvent, KeyboardId, KeyState, Mouse, MouseEvent, MouseId, Output, OutputId, ScrollAxis}; +use crate::backend::{ + BackendEvent, KeyState, Keyboard, KeyboardEvent, KeyboardId, Mouse, MouseEvent, MouseId, + Output, OutputId, ScrollAxis, +}; use crate::drm::drm::{Drm, DrmError}; use crate::drm::gbm::{GbmDevice, GbmError, GBM_BO_USE_RENDERING}; use crate::drm::{ModifiedFormat, INVALID_MODIFIER}; diff --git a/src/config.rs b/src/config.rs index f667e5fa..3fc88bf0 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,19 +1,19 @@ mod handler; use crate::backend::{KeyboardId, MouseId}; +use crate::config::handler::ConfigProxyHandler; +use crate::ifs::wl_seat::SeatId; use crate::utils::ptr_ext::PtrExt; use crate::{NumCell, State}; -use i4config::_private::ipc::{InitMessage, Request, V1InitMessage}; +use i4config::_private::ipc::{InitMessage, ServerMessage, V1InitMessage}; use i4config::_private::{bincode_ops, ConfigEntry, VERSION}; use i4config::keyboard::ModifiedKeySym; +use i4config::{InputDevice, Keyboard, Mouse, Seat}; use libloading::Library; use std::cell::Cell; use std::ptr; use std::rc::Rc; use thiserror::Error; -use i4config::{InputDevice, Keyboard, Mouse, Seat}; -use crate::config::handler::ConfigProxyHandler; -use crate::ifs::wl_seat::{SeatId}; #[derive(Debug, Error)] pub enum ConfigError { @@ -29,7 +29,7 @@ pub struct ConfigProxy { impl ConfigProxy { pub fn invoke_shortcut(&self, seat: SeatId, modsym: &ModifiedKeySym) { - self.handler.send(&Request::InvokeShortcut { + self.handler.send(&ServerMessage::InvokeShortcut { seat: Seat(seat.raw() as _), mods: modsym.mods, sym: modsym.sym, @@ -37,25 +37,25 @@ impl ConfigProxy { } pub fn new_keyboard(&self, kb: KeyboardId) { - self.handler.send(&Request::NewInputDevice { + self.handler.send(&ServerMessage::NewInputDevice { device: InputDevice::Keyboard(Keyboard(kb.raw() as _)), }); } pub fn new_mouse(&self, mouse: MouseId) { - self.handler.send(&Request::NewInputDevice { + self.handler.send(&ServerMessage::NewInputDevice { device: InputDevice::Mouse(Mouse(mouse.raw() as _)), }); } pub fn del_keyboard(&self, kb: KeyboardId) { - self.handler.send(&Request::DelInputDevice { + self.handler.send(&ServerMessage::DelInputDevice { device: InputDevice::Keyboard(Keyboard(kb.raw() as _)), }); } pub fn del_mouse(&self, mouse: MouseId) { - self.handler.send(&Request::DelInputDevice { + self.handler.send(&ServerMessage::DelInputDevice { device: InputDevice::Mouse(Mouse(mouse.raw() as _)), }); } @@ -110,7 +110,7 @@ impl ConfigProxy { ); data.client_data.set(client_data); } - data.send(&Request::Configure); + data.send(&ServerMessage::Configure); Self { handler: data } } diff --git a/src/config/handler.rs b/src/config/handler.rs index 1aa82510..dda0f345 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -1,16 +1,3 @@ -use std::cell::{Cell}; -use std::rc::Rc; -use bincode::error::DecodeError; -use libloading::Library; -use log::Level; -use thiserror::Error; -use i4config::_private::bincode_ops; -use i4config::_private::ipc::{Request, Response}; -use i4config::keyboard::keymap::Keymap; -use i4config::{Axis, Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat}; -use i4config::keyboard::mods::Modifiers; -use i4config::keyboard::syms::KeySym; -use crate::{ErrorFmt, NumCell, State}; use crate::backend::{KeyboardId, MouseId}; use crate::ifs::wl_seat::WlSeatGlobal; use crate::state::DeviceHandlerData; @@ -19,6 +6,19 @@ use crate::utils::copyhashmap::CopyHashMap; use crate::utils::debug_fn::debug_fn; use crate::utils::stack::Stack; use crate::xkbcommon::XkbKeymap; +use crate::{ErrorFmt, NumCell, State}; +use bincode::error::DecodeError; +use i4config::_private::bincode_ops; +use i4config::_private::ipc::{ClientMessage, Response, ServerMessage}; +use i4config::keyboard::keymap::Keymap; +use i4config::keyboard::mods::Modifiers; +use i4config::keyboard::syms::KeySym; +use i4config::{Axis, Direction, InputDevice, Keyboard, LogLevel, Mouse, Seat}; +use libloading::Library; +use log::Level; +use std::cell::Cell; +use std::rc::Rc; +use thiserror::Error; pub(super) struct ConfigProxyHandler { pub client_data: Cell<*const u8>, @@ -34,7 +34,7 @@ pub(super) struct ConfigProxyHandler { } impl ConfigProxyHandler { - pub fn send(&self, msg: &Request) { + pub fn send(&self, msg: &ServerMessage) { let mut buf = self.bufs.pop().unwrap_or_default(); buf.clear(); bincode::encode_into_std_write(msg, &mut buf, bincode_ops()).unwrap(); @@ -48,7 +48,13 @@ impl ConfigProxyHandler { self.next_id.fetch_add(1) } - fn handle_log_request(&self, level: LogLevel, msg: &str, file: Option<&str>, line: Option) -> Result<(), LogError> { + fn handle_log_request( + &self, + level: LogLevel, + msg: &str, + file: Option<&str>, + line: Option, + ) -> Result<(), LogError> { let level = match level { LogLevel::Error => Level::Error, LogLevel::Warn => Level::Warn, @@ -75,10 +81,10 @@ impl ConfigProxyHandler { let global_name = self.state.globals.name(); let seat = WlSeatGlobal::new(global_name, name, &self.state); self.state.globals.add_global(&self.state, &seat); - self.send(&Request::Response { + self.send(&ServerMessage::Response { response: Response::CreateSeat { seat: Seat(seat.id().raw() as _), - } + }, }); Ok(()) } @@ -90,11 +96,11 @@ impl ConfigProxyHandler { self.keymaps.set(id, keymap); (id, Ok(())) } - _ => { - (Keymap::INVALID, Err(ParseKeymapError::ParsingFailed)) - } + _ => (Keymap::INVALID, Err(ParseKeymapError::ParsingFailed)), }; - self.send(&Request::Response { response: Response::ParseKeymap { keymap } }); + self.send(&ServerMessage::Response { + response: Response::ParseKeymap { keymap }, + }); res } @@ -118,16 +124,18 @@ impl ConfigProxyHandler { fn handle_get_repeat_rate(&self, seat: Seat) -> Result<(), SeatGetRepeatRateError> { let seat = self.get_seat(seat)?; let (rate, delay) = seat.get_rate(); - self.send(&Request::Response { - response: Response::GetRepeatRate { - rate, - delay, - }, + self.send(&ServerMessage::Response { + response: Response::GetRepeatRate { rate, delay }, }); Ok(()) } - fn handle_set_repeat_rate(&self, seat: Seat, rate: i32, delay: i32) -> Result<(), SeatSetRepeatRateError> { + fn handle_set_repeat_rate( + &self, + seat: Seat, + rate: i32, + delay: i32, + ) -> Result<(), SeatSetRepeatRateError> { let seat = self.get_seat(seat)?; if rate < 0 { return Err(SeatSetRepeatRateError::NegativeRate); @@ -139,14 +147,23 @@ impl ConfigProxyHandler { Ok(()) } - fn get_device_handler_data(&self, device: InputDevice) -> Result, CphError> { + fn get_device_handler_data( + &self, + device: InputDevice, + ) -> Result, CphError> { let data = match device { - InputDevice::Keyboard(kb) => { - self.state.kb_handlers.borrow_mut().get(&KeyboardId::from_raw(kb.0 as _)).map(|d| d.data.clone()) - }, - InputDevice::Mouse(mouse) => { - self.state.mouse_handlers.borrow_mut().get(&MouseId::from_raw(mouse.0 as _)).map(|d| d.data.clone()) - } + InputDevice::Keyboard(kb) => self + .state + .kb_handlers + .borrow_mut() + .get(&KeyboardId::from_raw(kb.0 as _)) + .map(|d| d.data.clone()), + InputDevice::Mouse(mouse) => self + .state + .mouse_handlers + .borrow_mut() + .get(&MouseId::from_raw(mouse.0 as _)) + .map(|d| d.data.clone()), }; match data { Some(d) => Ok(d), @@ -184,10 +201,13 @@ impl ConfigProxyHandler { fn handle_get_split(&self, seat: Seat) -> Result<(), GetSplitError> { let seat = self.get_seat(seat)?; - self.send(&Request::Response { + self.send(&ServerMessage::Response { response: Response::GetSplit { - axis: seat.get_split().unwrap_or(ContainerSplit::Horizontal).into(), - } + axis: seat + .get_split() + .unwrap_or(ContainerSplit::Horizontal) + .into(), + }, }); Ok(()) } @@ -198,14 +218,19 @@ impl ConfigProxyHandler { Ok(()) } - fn handle_add_shortcut(&self, seat: Seat, mods: Modifiers, sym: KeySym) -> Result<(), AddShortcutError> { + fn handle_add_shortcut( + &self, + seat: Seat, + mods: Modifiers, + sym: KeySym, + ) -> Result<(), AddShortcutError> { let seat = self.get_seat(seat)?; seat.add_shortcut(mods, sym); Ok(()) } fn handle_get_input_devices(&self) -> Result<(), GetInputDevicesError> { - let mut res = vec!(); + let mut res = vec![]; { let devs = self.state.kb_handlers.borrow_mut(); for dev in devs.values() { @@ -218,7 +243,7 @@ impl ConfigProxyHandler { res.push(InputDevice::Mouse(Mouse(dev.id.raw() as _))); } } - self.send(&Request::Response { + self.send(&ServerMessage::Response { response: Response::GetInputDevices { devices: res }, }); Ok(()) @@ -232,12 +257,21 @@ impl ConfigProxyHandler { .map(|seat| Seat::from_raw(seat.id().raw() as _)) .collect() }; - self.send(&Request::Response { + self.send(&ServerMessage::Response { response: Response::GetSeats { seats }, }); Ok(()) } + fn handle_run(&self, prog: &str, args: Vec, env: Vec<(String, String)>) -> Result<(), RunError> { + let forker = match self.state.forker.get() { + Some(f) => f, + _ => return Err(RunError::NoForker), + }; + forker.spawn(prog.to_string(), args, env); + Ok(()) + } + pub fn handle_request(&self, msg: &[u8]) { if let Err(e) = self.handle_request_(msg) { log::error!("Could not handle client request: {}", ErrorFmt(e)); @@ -245,36 +279,40 @@ impl ConfigProxyHandler { } fn handle_request_(&self, msg: &[u8]) -> Result<(), CphError> { - let (request, _) = match bincode::decode_from_slice::(msg, bincode_ops()) { + let (request, _) = match bincode::decode_from_slice::(msg, bincode_ops()) + { Ok(msg) => msg, Err(e) => return Err(CphError::ParsingFailed(e)), }; match request { - Request::Log { + ClientMessage::Log { level, msg, file, line, } => self.handle_log_request(level, msg, file, line)?, - Request::CreateSeat { name } => self.handle_create_seat(name)?, - Request::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?, - Request::SeatSetKeymap { seat, keymap } => self.handle_set_keymap(seat, keymap)?, - Request::SeatGetRepeatRate { seat } => self.handle_get_repeat_rate(seat)?, - Request::SeatSetRepeatRate { seat, rate, delay } => self.handle_set_repeat_rate(seat, rate, delay)?, - Request::SetSeat { device, seat } => self.handle_set_seat(device, seat)?, - Request::GetSplit { seat } => self.handle_get_split(seat)?, - Request::SetSplit { seat, axis } => self.handle_set_split(seat, axis)?, - Request::AddShortcut { - seat, - mods, - sym, - } => self.handle_add_shortcut(seat, mods, sym)?, - Request::RemoveShortcut { .. } => {} - Request::Focus { seat, direction } => self.handle_focus(seat, direction)?, - Request::Move { seat, direction } => {} - Request::GetInputDevices => self.handle_get_input_devices()?, - Request::GetSeats => self.handle_get_seats()?, - m => return Err(CphError::UnexpectedMessage(format!("{:?}", m))), + ClientMessage::CreateSeat { name } => self.handle_create_seat(name)?, + ClientMessage::ParseKeymap { keymap } => self.handle_parse_keymap(keymap)?, + ClientMessage::SeatSetKeymap { seat, keymap } => { + self.handle_set_keymap(seat, keymap)? + } + ClientMessage::SeatGetRepeatRate { seat } => self.handle_get_repeat_rate(seat)?, + ClientMessage::SeatSetRepeatRate { seat, rate, delay } => { + self.handle_set_repeat_rate(seat, rate, delay)? + } + ClientMessage::SetSeat { device, seat } => self.handle_set_seat(device, seat)?, + ClientMessage::GetSplit { seat } => self.handle_get_split(seat)?, + ClientMessage::SetSplit { seat, axis } => self.handle_set_split(seat, axis)?, + ClientMessage::AddShortcut { seat, mods, sym } => { + self.handle_add_shortcut(seat, mods, sym)? + } + ClientMessage::RemoveShortcut { .. } => {} + ClientMessage::Focus { seat, direction } => self.handle_focus(seat, direction)?, + ClientMessage::Move { seat, direction } => {} + ClientMessage::GetInputDevices => self.handle_get_input_devices()?, + ClientMessage::GetSeats => self.handle_get_seats()?, + ClientMessage::RemoveSeat { .. } => {} + ClientMessage::Run { prog, args, env } => self.handle_run(prog, args, env)?, } Ok(()) } @@ -308,6 +346,8 @@ enum CphError { SetSplitError(#[from] SetSplitError), #[error("Could not process a `get_split` request")] GetSplitError(#[from] GetSplitError), + #[error("Could not process a `run` request")] + RunError(#[from] RunError), #[error("Device {0:?} does not exist")] DeviceDoesNotExist(InputDevice), #[error("Device {0:?} does not exist")] @@ -321,14 +361,10 @@ enum CphError { } #[derive(Debug, Error)] -enum LogError { - -} +enum LogError {} #[derive(Debug, Error)] -enum CreateSeatError { - -} +enum CreateSeatError {} #[derive(Debug, Error)] enum ParseKeymapError { @@ -351,14 +387,10 @@ enum AddShortcutError { efrom!(AddShortcutError, CphError); #[derive(Debug, Error)] -enum GetInputDevicesError { - -} +enum GetInputDevicesError {} #[derive(Debug, Error)] -enum GetSeatsError { - -} +enum GetSeatsError {} #[derive(Debug, Error)] enum SeatSetKeymapError { @@ -405,3 +437,9 @@ enum GetSplitError { CphError(#[from] Box), } efrom!(GetSplitError, CphError); + +#[derive(Debug, Error)] +enum RunError { + #[error("The ol' forker is not available")] + NoForker, +} diff --git a/src/forker.rs b/src/forker.rs new file mode 100644 index 00000000..9bb9685f --- /dev/null +++ b/src/forker.rs @@ -0,0 +1,344 @@ +mod clone3; + +use crate::async_engine::{AsyncFd, SpawnedFuture}; +use crate::forker::clone3::{fork_with_pidfd, Forked}; +use crate::utils::buffd::{BufFdIn, BufFdOut}; +use crate::utils::copyhashmap::CopyHashMap; +use crate::utils::vec_ext::VecExt; +use crate::{AsyncEngine, AsyncQueue, ErrorFmt, EventLoop, State, Wheel}; +use bincode::{Decode, Encode}; +use i4config::_private::bincode_ops; +use log::Level; +use parking_lot::Mutex; +use std::cell::Cell; +use std::ffi::OsStr; +use std::io::Read; +use std::io::Write; +use std::os::unix::ffi::OsStrExt; +use std::rc::Rc; +use thiserror::Error; +use uapi::{c, pipe2, IntoUstr, OwnedFd, UstrPtr}; + +pub struct ForkerProxy { + pidfd: Rc, + pid: c::pid_t, + socket: Rc, + task_in: Cell>>, + task_out: Cell>>, + task_proc: Cell>>, + outgoing: AsyncQueue, +} + +#[derive(Debug, Error)] +pub enum ForkerError { + #[error("Could not create a socketpair")] + Socketpair(#[source] std::io::Error), + #[error("Could not fork")] + Fork(#[source] std::io::Error), +} + +impl ForkerProxy { + pub fn create() -> Result { + let (parent, child) = match uapi::socketpair( + c::AF_UNIX, + c::SOCK_STREAM | c::SOCK_CLOEXEC | c::SOCK_NONBLOCK, + 0, + ) { + Ok(o) => o, + Err(e) => return Err(ForkerError::Socketpair(e.into())), + }; + match fork_with_pidfd(false)? { + Forked::Parent { pid, pidfd } => Ok(ForkerProxy { + pidfd: Rc::new(pidfd), + pid, + socket: Rc::new(parent), + task_in: Cell::new(None), + task_out: Cell::new(None), + task_proc: Cell::new(None), + outgoing: Default::default(), + }), + Forked::Child { .. } => Forker::handle(child), + } + } + + pub fn install(self: &Rc, state: &Rc) { + state.forker.set(Some(self.clone())); + let socket = state.eng.fd(&self.socket).unwrap(); + self.task_proc.set(Some( + state.eng.spawn(self.clone().check_process(state.clone())), + )); + self.task_in + .set(Some(state.eng.spawn(self.clone().incoming(socket.clone())))); + self.task_out.set(Some( + state + .eng + .spawn(self.clone().outgoing(state.clone(), socket.clone())), + )); + } + + pub fn setenv(&self, key: &[u8], val: &[u8]) { + self.outgoing.push(ServerMessage::SetEnv { + var: key.to_vec(), + val: val.to_vec(), + }) + } + + pub fn spawn(&self, prog: String, args: Vec, env: Vec<(String, String)>) { + self.outgoing.push(ServerMessage::Spawn { + prog, + args, + env, + }) + } + + async fn incoming(self: Rc, socket: AsyncFd) { + let mut buffd = BufFdIn::new(socket); + let mut buf = vec![]; + loop { + let mut len = 0usize; + if let Err(e) = buffd.read_full(&mut len).await { + log::error!("Cannot read from the ol' forker: {}", ErrorFmt(e)); + self.task_in.take(); + return; + } + buf.clear(); + buf.reserve(len); + let space = buf.split_at_spare_mut_ext().1; + buffd.read_full(&mut space[..len]).await.unwrap(); + unsafe { + buf.set_len(len); + } + let (msg, _) = + bincode::decode_from_slice::(&buf, bincode_ops()).unwrap(); + self.handle_msg(msg); + } + } + + fn handle_msg(&self, msg: ForkerMessage) { + match msg { + ForkerMessage::Log { level, msg } => self.handle_log(level, &msg), + } + } + + fn handle_log(&self, level: usize, msg: &str) { + let level = match level { + 1 => Level::Error, + 2 => Level::Warn, + 3 => Level::Info, + 4 => Level::Debug, + 5 => Level::Trace, + _ => Level::Error, + }; + log::log!(level, "{}", msg); + } + + async fn outgoing(self: Rc, state: Rc, socket: AsyncFd) { + let mut buffd = BufFdOut::new(socket); + let mut buf = vec![]; + let mut fds = vec![]; + loop { + let msg = self.outgoing.pop().await; + buf.clear(); + buf.extend_from_slice(uapi::as_bytes(&0usize)); + let len = bincode::encode_into_std_write(&msg, &mut buf, bincode_ops()).unwrap(); + let _ = (&mut buf[..]).write_all(uapi::as_bytes(&len)); + if let Err(e) = buffd.flush2(&buf, &mut fds).await { + log::error!("Could not write to the ol' forker: {}", ErrorFmt(e)); + state.forker.set(None); + self.task_out.take(); + return; + } + } + } + + async fn check_process(self: Rc, state: Rc) { + let pidfd = state.eng.fd(&self.pidfd).unwrap(); + let _ = pidfd.readable().await; + let _ = uapi::waitpid(self.pid, 0); + log::error!("The ol' forker died. Cannot spawn further processes."); + state.forker.set(None); + self.task_out.take(); + self.task_proc.take(); + } +} + +#[derive(Encode, Decode)] +enum ServerMessage { + SetEnv { var: Vec, val: Vec }, + Spawn { prog: String, args: Vec, env: Vec<(String, String)> }, +} + +#[derive(Encode, Decode)] +enum ForkerMessage { + Log { level: usize, msg: String }, +} + +struct Forker { + socket: AsyncFd, + ae: Rc, + outgoing: AsyncQueue, + pending_spawns: CopyHashMap>, +} + +impl Forker { + fn handle(mut socket: OwnedFd) -> ! { + std::env::set_var("XDG_SESSION_TYPE", "wayland"); + std::env::remove_var("DISPLAY"); + std::env::remove_var("WAYLAND_DISPLAY"); + setup_deathsig(); + reset_signals(); + socket = setup_fds(socket); + std::panic::set_hook({ + let socket = Mutex::new(uapi::fcntl_dupfd_cloexec(socket.raw(), 0).unwrap()); + Box::new(move |pi| { + let msg = ForkerMessage::Log { + level: log::Level::Error as _, + msg: format!("The ol' forker panicked: {}", pi), + }; + let msg = bincode::encode_to_vec(&msg, bincode_ops()).unwrap(); + let _ = socket.lock().write_all(&msg); + }) + }); + let el = EventLoop::new().unwrap(); + let wheel = Wheel::install(&el).unwrap(); + let ae = AsyncEngine::install(&el, &wheel).unwrap(); + let forker = Rc::new(Forker { + socket: ae.fd(&Rc::new(socket)).unwrap(), + ae: ae.clone(), + outgoing: Default::default(), + pending_spawns: Default::default(), + }); + let _f1 = ae.spawn(forker.clone().incoming()); + let _f2 = ae.spawn(forker.clone().outgoing()); + let _ = el.run(); + unreachable!(); + } + + async fn outgoing(self: Rc) { + let mut buffd = BufFdOut::new(self.socket.clone()); + let mut buf = vec![]; + let mut fds = vec![]; + loop { + let msg = self.outgoing.pop().await; + buf.clear(); + buf.extend_from_slice(uapi::as_bytes(&0usize)); + let len = bincode::encode_into_std_write(&msg, &mut buf, bincode_ops()).unwrap(); + let _ = (&mut buf[..]).write_all(uapi::as_bytes(&len)); + buffd.flush2(&buf, &mut fds).await.unwrap(); + } + } + + async fn incoming(self: Rc) { + let mut buffd = BufFdIn::new(self.socket.clone()); + let mut buf = vec![]; + loop { + let mut len = 0usize; + buffd.read_full(&mut len).await.unwrap(); + buf.clear(); + buf.reserve(len); + let space = buf.split_at_spare_mut_ext().1; + buffd.read_full(&mut space[..len]).await.unwrap(); + unsafe { + buf.set_len(len); + } + let (msg, _) = + bincode::decode_from_slice::(&buf, bincode_ops()).unwrap(); + self.handle_msg(msg); + } + } + + fn handle_msg(self: &Rc, msg: ServerMessage) { + match msg { + ServerMessage::SetEnv { var, val } => self.handle_set_env(&var, &val), + ServerMessage::Spawn { prog, args, env } => self.handle_spawn(prog, args, env), + } + } + + fn handle_set_env(self: &Rc, var: &[u8], val: &[u8]) { + std::env::set_var(OsStr::from_bytes(var), OsStr::from_bytes(val)); + } + + fn handle_spawn(self: &Rc, prog: String, args: Vec, env: Vec<(String, String)>) { + let (mut read, mut write) = pipe2(c::O_CLOEXEC).unwrap(); + let res = match fork_with_pidfd(false) { + Ok(o) => o, + Err(e) => { + self.outgoing.push(ForkerMessage::Log { + level: log::Level::Error as usize, + msg: ErrorFmt(e).to_string(), + }); + return; + } + }; + match res { + Forked::Parent { pidfd, pid } => { + drop(write); + let slf = self.clone(); + let spawn = self.ae.spawn(async move { + let pidfd = slf.ae.fd(&Rc::new(pidfd)).unwrap(); + let _ = pidfd.readable().await; + let mut s = String::new(); + let _ = read.read_to_string(&mut s); + if s.len() > 0 { + slf.outgoing.push(ForkerMessage::Log { + level: log::Level::Error as _, + msg: format!("Could not spawn `{}`: {}", prog, s), + }); + } + slf.pending_spawns.remove(&pid); + }); + self.pending_spawns.set(pid, spawn); + } + Forked::Child { .. } => { + unsafe { + c::signal(c::SIGCHLD, c::SIG_DFL); + } + for (key, val) in env { + std::env::set_var(&key, &val); + } + let prog = prog.into_ustr(); + let mut argsnt = UstrPtr::new(); + argsnt.push(&prog); + for arg in args { + argsnt.push(arg); + } + if let Err(e) = uapi::execvp(&prog, &argsnt) { + let _ = write.write_all(std::io::Error::from(e).to_string().as_bytes()); + } + std::process::exit(1); + } + } + } +} + +fn setup_fds(mut socket: OwnedFd) -> OwnedFd { + if socket.raw() != 0 { + uapi::dup3(socket.unwrap(), 0, 0).unwrap(); + socket = OwnedFd::new(0); + } + uapi::close_range(1, c::c_uint::MAX, 0).unwrap(); + uapi::dup3(socket.raw(), 3, c::O_CLOEXEC).unwrap(); + socket = OwnedFd::new(3); + let fd = uapi::open("/dev/null", c::O_RDWR, 0).unwrap().unwrap(); + assert!(fd == 0); + uapi::dup2(0, 1).unwrap(); + uapi::dup2(0, 2).unwrap(); + socket +} + +fn reset_signals() { + const NSIG: c::c_int = 64; + unsafe { + for sig in 1..=NSIG { + c::signal(sig, c::SIG_DFL); + } + c::signal(c::SIGCHLD, c::SIG_IGN); + } +} + +fn setup_deathsig() { + unsafe { + let res = c::prctl(c::PR_SET_PDEATHSIG, c::SIGKILL as c::c_ulong); + uapi::map_err!(res).unwrap(); + } +} diff --git a/src/forker/clone3.rs b/src/forker/clone3.rs new file mode 100644 index 00000000..0e4804af --- /dev/null +++ b/src/forker/clone3.rs @@ -0,0 +1,56 @@ +use crate::forker::ForkerError; +use std::mem; +use uapi::{c, OwnedFd}; + +#[derive(Default, Copy, Clone)] +#[allow(non_camel_case_types, dead_code)] +struct clone_args { + flags: u64, + pidfd: u64, + child_tid: u64, + parent_tid: u64, + exit_signal: u64, + stack: u64, + stack_size: u64, + tls: u64, + set_tid: u64, + set_tid_size: u64, + cgroup: u64, +} + +pub enum Forked { + Parent { pid: c::pid_t, pidfd: OwnedFd }, + Child { pidfd: Option }, +} + +pub fn fork_with_pidfd(pidfd_for_child: bool) -> Result { + let mut pidfd: c::c_int = 0; + let mut args = clone_args { + flags: c::CLONE_PIDFD as u64, + pidfd: (&mut pidfd as *mut c::c_int) as _, + ..Default::default() + }; + let mut child_pidfd = None; + if pidfd_for_child { + child_pidfd = Some(uapi::pidfd_open(uapi::getpid(), 0).unwrap()); + } + unsafe { + let pid = c::syscall( + c::SYS_clone3, + &mut args as *const _ as usize, + mem::size_of::(), + ); + if let Err(e) = uapi::map_err!(pid) { + return Err(ForkerError::Fork(e.into())); + } + let res = if pid == 0 { + Forked::Child { pidfd: child_pidfd } + } else { + Forked::Parent { + pid: pid as _, + pidfd: OwnedFd::new(pidfd), + } + }; + Ok(res) + } +} diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 04702a40..cd9cfdfd 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -4,6 +4,7 @@ pub mod wl_keyboard; pub mod wl_pointer; pub mod wl_touch; +use crate::async_engine::SpawnedFuture; use crate::client::{Client, ClientError, ClientId}; use crate::cursor::{Cursor, KnownCursor}; use crate::fixed::Fixed; @@ -38,6 +39,7 @@ use crate::{ErrorFmt, NumCell, State}; use ahash::{AHashMap, AHashSet}; pub use event_handling::NodeSeatState; use i4config::keyboard::mods::Modifiers; +use i4config::Direction; use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::mem; @@ -45,8 +47,6 @@ use std::ops::DerefMut; use std::rc::Rc; use thiserror::Error; use uapi::{c, Errno, OwnedFd}; -use i4config::{ Direction}; -use crate::async_engine::SpawnedFuture; const POINTER: u32 = 1; const KEYBOARD: u32 = 2; @@ -119,11 +119,7 @@ pub struct WlSeatGlobal { } impl WlSeatGlobal { - pub fn new( - name: GlobalName, - seat_name: &str, - state: &Rc, - ) -> Rc { + pub fn new(name: GlobalName, seat_name: &str, state: &Rc) -> Rc { let slf = Rc::new(Self { id: state.seat_ids.next(), name, @@ -167,7 +163,8 @@ impl WlSeatGlobal { } pub fn mark_last_active(self: &Rc) { - self.queue_link.set(Some(self.state.seat_queue.add_last(self.clone()))); + self.queue_link + .set(Some(self.state.seat_queue.add_last(self.clone()))); } pub fn set_keymap(&self, keymap: &Rc) { @@ -464,7 +461,11 @@ impl WlSeat { self.client.add_client_obj(&p)?; self.keyboards.set(req.id, p.clone()); let keymap = self.global.kb_map.get(); - p.send_keymap(wl_keyboard::XKB_V1, self.keymap_fd(&keymap)?, keymap.map_len as _); + p.send_keymap( + wl_keyboard::XKB_V1, + self.keymap_fd(&keymap)?, + keymap.map_len as _, + ); if self.version >= REPEAT_INFO_SINCE { let (rate, delay) = self.global.repeat_rate.get(); p.send_repeat_info(rate, delay); @@ -484,12 +485,7 @@ impl WlSeat { let mut pos = 0; while pos < target { let rem = target - pos; - let res = uapi::sendfile( - fd.raw(), - keymap.map.raw(), - Some(&mut pos), - rem as usize, - ); + let res = uapi::sendfile(fd.raw(), keymap.map.raw(), Some(&mut pos), rem as usize); match res { Ok(_) | Err(Errno(c::EINTR)) => {} Err(e) => return Err(WlKeyboardError::KeymapCopy(e.into())), diff --git a/src/ifs/wl_seat/event_handling.rs b/src/ifs/wl_seat/event_handling.rs index 02ba077c..1eb2c7b8 100644 --- a/src/ifs/wl_seat/event_handling.rs +++ b/src/ifs/wl_seat/event_handling.rs @@ -1,4 +1,4 @@ -use crate::backend::{KeyboardEvent, KeyState, MouseEvent, OutputId, ScrollAxis}; +use crate::backend::{KeyState, KeyboardEvent, MouseEvent, OutputId, ScrollAxis}; use crate::client::{Client, ClientId}; use crate::fixed::Fixed; use crate::ifs::ipc; @@ -6,7 +6,7 @@ use crate::ifs::ipc::wl_data_device::WlDataDevice; use crate::ifs::ipc::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1; use crate::ifs::wl_seat::wl_keyboard::WlKeyboard; use crate::ifs::wl_seat::wl_pointer::{WlPointer, POINTER_FRAME_SINCE_VERSION}; -use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, WlSeat, WlSeatGlobal, SeatId}; +use crate::ifs::wl_seat::{wl_keyboard, wl_pointer, Dnd, SeatId, WlSeat, WlSeatGlobal}; use crate::ifs::wl_surface::xdg_surface::xdg_popup::XdgPopup; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel; use crate::ifs::wl_surface::xdg_surface::XdgSurface; diff --git a/src/ifs/wl_seat/wl_keyboard.rs b/src/ifs/wl_seat/wl_keyboard.rs index 9dbdfff2..d1e97514 100644 --- a/src/ifs/wl_seat/wl_keyboard.rs +++ b/src/ifs/wl_seat/wl_keyboard.rs @@ -8,7 +8,7 @@ use crate::wire::wl_keyboard::*; use crate::wire::{WlKeyboardId, WlSurfaceId}; use std::rc::Rc; use thiserror::Error; -use uapi::{OwnedFd}; +use uapi::OwnedFd; pub const REPEAT_INFO_SINCE: u32 = 4; diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index a4406cc6..302f8ab4 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -2,6 +2,7 @@ pub mod cursor; pub mod wl_subsurface; pub mod xdg_surface; +use crate::backend::{KeyState, ScrollAxis}; use crate::client::{Client, ClientError, RequestParser}; use crate::fixed::Fixed; use crate::ifs::wl_buffer::WlBuffer; @@ -25,14 +26,13 @@ use crate::wire::{WlOutputId, WlSurfaceId}; use crate::xkbcommon::ModifierState; use crate::NumCell; use ahash::AHashMap; +use i4config::Direction; use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Formatter}; use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; use thiserror::Error; -use i4config::{ Direction}; -use crate::backend::{KeyState, ScrollAxis}; #[allow(dead_code)] const INVALID_SCALE: u32 = 0; diff --git a/src/ifs/wl_surface/xdg_surface.rs b/src/ifs/wl_surface/xdg_surface.rs index f67ce90d..f99aded1 100644 --- a/src/ifs/wl_surface/xdg_surface.rs +++ b/src/ifs/wl_surface/xdg_surface.rs @@ -21,11 +21,11 @@ use crate::utils::smallmap::SmallMap; use crate::wire::xdg_surface::*; use crate::wire::{WlSurfaceId, XdgPopupId, XdgSurfaceId}; use crate::NumCell; +use i4config::Direction; use std::cell::Cell; use std::fmt::Debug; use std::rc::Rc; use thiserror::Error; -use i4config::{Direction}; #[allow(dead_code)] const NOT_CONSTRUCTED: u32 = 1; diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs index 42aaeeca..1f4ea6ec 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel.rs @@ -19,6 +19,7 @@ use crate::wire::xdg_toplevel::*; use crate::wire::XdgToplevelId; use crate::{bugs, NumCell}; use ahash::{AHashMap, AHashSet}; +use i4config::Direction; use num_derive::FromPrimitive; use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Formatter}; @@ -26,7 +27,6 @@ use std::mem; use std::ops::Deref; use std::rc::Rc; use thiserror::Error; -use i4config::{Direction}; #[derive(Copy, Clone, Debug, FromPrimitive)] pub enum ResizeEdge { diff --git a/src/main.rs b/src/main.rs index 97a9487f..bdb58f48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,7 @@ use crate::backends::xorg::{XorgBackend, XorgBackendError}; use crate::client::Clients; use crate::clientmem::ClientMemError; use crate::event_loop::EventLoopError; +use crate::forker::ForkerError; use crate::globals::Globals; use crate::ifs::wl_compositor::WlCompositorGlobal; use crate::ifs::wl_shm::WlShmGlobal; @@ -29,6 +30,7 @@ use crate::utils::errorfmt::ErrorFmt; use crate::utils::numcell::NumCell; use crate::utils::queue::AsyncQueue; use crate::wheel::WheelError; +use crate::xkbcommon::XkbContext; use acceptor::Acceptor; use async_engine::AsyncEngine; use event_loop::EventLoop; @@ -38,7 +40,6 @@ use std::ops::Deref; use std::rc::Rc; use thiserror::Error; use wheel::Wheel; -use crate::xkbcommon::XkbContext; #[macro_use] mod macros; @@ -56,6 +57,7 @@ mod cursor; mod drm; mod event_loop; mod fixed; +mod forker; mod format; mod globals; mod ifs; @@ -104,9 +106,12 @@ enum MainError { XorgBackendError(#[from] XorgBackendError), #[error("The render backend caused an error")] RenderError(#[from] RenderError), + #[error("The ol' forker caused an error")] + ForkerError(#[from] ForkerError), } fn main_() -> Result<(), MainError> { + let forker = Rc::new(forker::ForkerProxy::create()?); leaks::init(); render::init()?; clientmem::init()?; @@ -119,6 +124,7 @@ fn main_() -> Result<(), MainError> { let node_ids = NodeIds::default(); let state = Rc::new(State { xkb_ctx, + forker: Default::default(), default_keymap: xkb_keymap, eng: engine.clone(), el: el.clone(), @@ -145,11 +151,13 @@ fn main_() -> Result<(), MainError> { mouse_ids: Default::default(), kb_handlers: Default::default(), }); + forker.install(&state); let config = config::ConfigProxy::default(&state); state.config.set(Some(Rc::new(config))); let _global_event_handler = engine.spawn(tasks::handle_backend_events(state.clone())); let _slow_client_handler = engine.spawn(tasks::handle_slow_clients(state.clone())); - Acceptor::install(&state)?; + let socket_path = Acceptor::install(&state)?; + forker.setenv(b"WAYLAND_DISPLAY", socket_path.as_bytes()); let _backend = XorgBackend::new(&state)?; el.run()?; state.clients.clear(); diff --git a/src/state.rs b/src/state.rs index 1dc139f8..007f1676 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,9 +1,12 @@ use crate::async_engine::{AsyncEngine, SpawnedFuture}; -use crate::backend::{BackendEvent, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, OutputIds}; +use crate::backend::{ + BackendEvent, KeyboardId, KeyboardIds, MouseId, MouseIds, OutputId, OutputIds, +}; use crate::client::{Client, Clients}; use crate::config::ConfigProxy; use crate::cursor::ServerCursors; use crate::event_loop::EventLoop; +use crate::forker::ForkerProxy; use crate::globals::{Globals, GlobalsError, WaylandGlobal}; use crate::ifs::wl_output::WlOutputGlobal; use crate::ifs::wl_seat::{SeatIds, WlSeatGlobal}; @@ -15,14 +18,15 @@ use crate::utils::copyhashmap::CopyHashMap; use crate::utils::linkedlist::LinkedList; use crate::utils::numcell::NumCell; use crate::utils::queue::AsyncQueue; +use crate::xkbcommon::XkbKeymap; use crate::{ErrorFmt, Wheel, XkbContext}; use ahash::AHashMap; use std::cell::{Cell, RefCell}; use std::rc::Rc; -use crate::xkbcommon::XkbKeymap; pub struct State { pub xkb_ctx: XkbContext, + pub forker: CloneCell>>, pub default_keymap: Rc, pub eng: Rc, pub el: Rc, @@ -53,13 +57,13 @@ pub struct State { pub struct MouseData { pub handler: SpawnedFuture<()>, pub id: MouseId, - pub data: Rc + pub data: Rc, } pub struct KeyboardData { pub handler: SpawnedFuture<()>, pub id: KeyboardId, - pub data: Rc + pub data: Rc, } pub struct DeviceHandlerData { diff --git a/src/tasks/backend.rs b/src/tasks/backend.rs index 859815b8..e95ea1ba 100644 --- a/src/tasks/backend.rs +++ b/src/tasks/backend.rs @@ -1,8 +1,8 @@ use crate::backend::{BackendEvent, Output}; +use crate::tasks::device; use crate::tasks::output::OutputHandler; use crate::State; use std::rc::Rc; -use crate::tasks::device; pub struct BackendEventHandler { pub state: Rc, diff --git a/src/tasks/device.rs b/src/tasks/device.rs index 9db48328..a7656e76 100644 --- a/src/tasks/device.rs +++ b/src/tasks/device.rs @@ -1,11 +1,11 @@ +use crate::async_engine::SpawnedFuture; use crate::backend::{Keyboard, KeyboardEvent, Mouse, MouseEvent}; +use crate::config::ConfigProxy; use crate::ifs::wl_seat::WlSeatGlobal; +use crate::state::{DeviceHandlerData, KeyboardData, MouseData}; use crate::utils::asyncevent::AsyncEvent; use crate::State; use std::rc::Rc; -use crate::async_engine::SpawnedFuture; -use crate::config::ConfigProxy; -use crate::state::{DeviceHandlerData, KeyboardData, MouseData}; pub trait DeviceApi: 'static { type Event; @@ -40,11 +40,14 @@ impl DeviceApi for dyn Keyboard { } fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc) { - state.kb_handlers.borrow_mut().insert(self.id(), KeyboardData { - handler, - id: self.id(), - data, - }); + state.kb_handlers.borrow_mut().insert( + self.id(), + KeyboardData { + handler, + id: self.id(), + data, + }, + ); } fn remove(&self, state: &State) { @@ -80,11 +83,14 @@ impl DeviceApi for dyn Mouse { } fn add(&self, state: &State, handler: SpawnedFuture<()>, data: Rc) { - state.mouse_handlers.borrow_mut().insert(self.id(), MouseData { - handler, - id: self.id(), - data, - }); + state.mouse_handlers.borrow_mut().insert( + self.id(), + MouseData { + handler, + id: self.id(), + data, + }, + ); } fn remove(&self, state: &State) { diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index ba486682..4073466a 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -1,7 +1,7 @@ mod backend; +mod device; mod output; mod slow_clients; -mod device; use crate::tasks::backend::BackendEventHandler; use crate::tasks::slow_clients::SlowClientHandler; diff --git a/src/tree/container.rs b/src/tree/container.rs index 452b3826..32c7baea 100644 --- a/src/tree/container.rs +++ b/src/tree/container.rs @@ -1,7 +1,7 @@ -use crate::backend::{KeyState}; +use crate::backend::KeyState; use crate::cursor::KnownCursor; use crate::fixed::Fixed; -use crate::ifs::wl_seat::{NodeSeatState, WlSeatGlobal, BTN_LEFT, SeatId}; +use crate::ifs::wl_seat::{NodeSeatState, SeatId, WlSeatGlobal, BTN_LEFT}; use crate::rect::Rect; use crate::render::Renderer; use crate::tree::{FindTreeResult, FoundNode, Node, NodeId, WorkspaceNode}; @@ -9,12 +9,12 @@ use crate::utils::clonecell::CloneCell; use crate::utils::linkedlist::{LinkedList, LinkedNode, NodeRef}; use crate::{NumCell, State}; use ahash::AHashMap; +use i4config::{Axis, Direction}; use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Formatter}; use std::mem; use std::ops::DerefMut; use std::rc::Rc; -use i4config::{Axis, Direction}; #[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] @@ -462,7 +462,12 @@ impl Node for ContainerNode { } } - fn move_focus_from_child(&self, seat: &Rc, child: &dyn Node, direction: Direction) { + fn move_focus_from_child( + &self, + seat: &Rc, + child: &dyn Node, + direction: Direction, + ) { let children = self.child_nodes.borrow_mut(); let child = match children.get(&child.id()) { Some(c) => c, @@ -473,7 +478,9 @@ impl Node for ContainerNode { ContainerSplit::Vertical => matches!(direction, Direction::Up | Direction::Down), }; if !in_line { - self.parent.get().move_focus_from_child(seat, self, direction); + self.parent + .get() + .move_focus_from_child(seat, self, direction); return; } let prev = match direction { @@ -484,12 +491,14 @@ impl Node for ContainerNode { }; let sibling = match prev { true => child.prev(), - false => child.next() + false => child.next(), }; let sibling = match sibling { Some(s) => s, None => { - self.parent.get().move_focus_from_child(seat, self, direction); + self.parent + .get() + .move_focus_from_child(seat, self, direction); return; } }; diff --git a/src/tree/mod.rs b/src/tree/mod.rs index 96980a3a..e25f8347 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -13,11 +13,11 @@ use crate::utils::linkedlist::{LinkedList, LinkedNode}; use crate::xkbcommon::ModifierState; use crate::NumCell; pub use container::*; +use i4config::Direction; use std::cell::{Cell, RefCell}; use std::fmt::{Debug, Display, Formatter}; use std::ops::Deref; use std::rc::Rc; -use i4config::{Direction}; pub use workspace::*; mod container; @@ -93,7 +93,12 @@ pub trait Node { let _ = direction; } - fn move_focus_from_child(&self, seat: &Rc, child: &dyn Node, direction: Direction) { + fn move_focus_from_child( + &self, + seat: &Rc, + child: &dyn Node, + direction: Direction, + ) { let _ = seat; let _ = direction; let _ = child; diff --git a/src/utils/buffd/buf_out.rs b/src/utils/buffd/buf_out.rs index cfd3483e..8deae34b 100644 --- a/src/utils/buffd/buf_out.rs +++ b/src/utils/buffd/buf_out.rs @@ -94,7 +94,6 @@ impl BufFdOut { ) -> Result<(), BufFdError> { while buf.read_pos < buf.write_pos { if self.flush_sync(buf)? { - self.fd.writable().await?; if timeout.is_none() { *timeout = Some(self.fd.eng().timeout(5000)?.fuse()); } @@ -157,6 +156,60 @@ impl BufFdOut { } Ok(false) } + + pub async fn flush2(&mut self, buf: &[u8], fds: &mut Vec) -> Result<(), BufFdError> { + let mut read_pos = 0; + while read_pos < buf.len() { + if self.flush_sync2(&mut read_pos, buf, fds)? { + self.fd.writable().await?; + } + } + Ok(()) + } + + fn flush_sync2( + &mut self, + read_pos: &mut usize, + buf: &[u8], + fds: &mut Vec, + ) -> Result { + let mut cmsg_len = 0; + let mut fds_opt = None; + if fds.len() > 0 { + self.fd_ids.clear(); + self.fd_ids.extend(fds.iter().map(|f| f.raw())); + let hdr = c::cmsghdr { + cmsg_len: 0, + cmsg_level: c::SOL_SOCKET, + cmsg_type: c::SCM_RIGHTS, + }; + let mut cmsg_buf = &mut self.cmsg_buf[..]; + cmsg_len = uapi::cmsg_write(&mut cmsg_buf, hdr, &self.fd_ids[..]).unwrap(); + fds_opt = Some(fds); + } + while *read_pos < buf.len() { + let buf = &buf[*read_pos..]; + let hdr = uapi::Msghdr { + iov: slice::from_ref(&buf), + control: Some(&self.cmsg_buf[..cmsg_len]), + name: uapi::sockaddr_none_ref(), + }; + let bytes_sent = + match uapi::sendmsg(self.fd.raw(), &hdr, c::MSG_DONTWAIT | c::MSG_NOSIGNAL) { + Ok(b) => { + if let Some(fds) = fds_opt.take() { + fds.clear(); + } + b + } + Err(Errno(c::EAGAIN)) => return Ok(true), + Err(Errno(c::ECONNRESET)) => return Err(BufFdError::Closed), + Err(e) => return Err(BufFdError::Io(e.into())), + }; + *read_pos += bytes_sent; + } + Ok(false) + } } impl Drop for OutBuffer { diff --git a/src/utils/copyhashmap.rs b/src/utils/copyhashmap.rs index 73213bfa..05eae02c 100644 --- a/src/utils/copyhashmap.rs +++ b/src/utils/copyhashmap.rs @@ -15,7 +15,7 @@ impl Default for CopyHashMap { } } -impl CopyHashMap { +impl CopyHashMap { pub fn new() -> Self { Self::default() } @@ -24,7 +24,10 @@ impl CopyHashMap { self.map.borrow_mut().insert(k, v); } - pub fn get(&self, k: &K) -> Option { + pub fn get(&self, k: &K) -> Option + where + V: Clone, + { self.map.borrow_mut().get(k).cloned() } diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs index 33e5c1c7..d01b1d6f 100644 --- a/src/utils/linkedlist.rs +++ b/src/utils/linkedlist.rs @@ -219,7 +219,8 @@ impl NodeRef { } fn peer(&self, peer: F) -> Option> - where F: FnOnce(&NodeData) -> &Cell>>, + where + F: FnOnce(&NodeData) -> &Cell>>, { unsafe { let data = self.data.as_ref(); diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 29c14367..ff6e52b5 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -10,5 +10,5 @@ pub mod numcell; pub mod ptr_ext; pub mod queue; pub mod smallmap; -pub mod vec_ext; pub mod stack; +pub mod vec_ext; diff --git a/src/utils/queue.rs b/src/utils/queue.rs index 902fdd27..c281c58e 100644 --- a/src/utils/queue.rs +++ b/src/utils/queue.rs @@ -10,6 +10,12 @@ pub struct AsyncQueue { waiters: RefCell>, } +impl Default for AsyncQueue { + fn default() -> Self { + Self::new() + } +} + impl AsyncQueue { pub fn new() -> Self { Self { diff --git a/src/utils/stack.rs b/src/utils/stack.rs index 382cd70b..d2c82491 100644 --- a/src/utils/stack.rs +++ b/src/utils/stack.rs @@ -1,5 +1,5 @@ -use std::cell::UnsafeCell; use crate::utils::ptr_ext::MutPtrExt; +use std::cell::UnsafeCell; pub struct Stack { vec: UnsafeCell>, @@ -21,8 +21,6 @@ impl Stack { } pub fn pop(&self) -> Option { - unsafe { - self.vec.get().deref_mut().pop() - } + unsafe { self.vec.get().deref_mut().pop() } } } diff --git a/src/xkbcommon/mod.rs b/src/xkbcommon/mod.rs index b69c7c6b..ba8e8d8d 100644 --- a/src/xkbcommon/mod.rs +++ b/src/xkbcommon/mod.rs @@ -124,8 +124,7 @@ impl XkbContext { } fn raw_to_map(raw: *mut xkb_keymap) -> Result, XkbCommonError> { - let res = - unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) }; + let res = unsafe { xkb_keymap_get_as_string(raw, XKB_KEYMAP_FORMAT_TEXT_V1.raw() as _) }; if res.is_null() { unsafe { xkb_keymap_unref(raw); @@ -143,7 +142,8 @@ impl XkbContext { uapi::fcntl_add_seals( memfd.raw(), c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE, - ).unwrap(); + ) + .unwrap(); Ok(Rc::new(XkbKeymap { keymap: raw, map: Rc::new(memfd), @@ -153,7 +153,13 @@ impl XkbContext { pub fn keymap_from_str(&self, s: &str) -> Result, XkbCommonError> { unsafe { - let keymap = xkb_keymap_new_from_buffer(self.context, s.as_bytes().as_ptr(), s.len(), XKB_KEYMAP_FORMAT_TEXT_V1.raw(), 0); + let keymap = xkb_keymap_new_from_buffer( + self.context, + s.as_bytes().as_ptr(), + s.len(), + XKB_KEYMAP_FORMAT_TEXT_V1.raw(), + 0, + ); if keymap.is_null() { return Err(XkbCommonError::KeymapFromBuffer); }