From 344a1997c7988feb95575b1717dc0d6a10409311 Mon Sep 17 00:00:00 2001 From: Greg Depoire--Ferrer <56923875+greg904@users.noreply.github.com> Date: Fri, 18 Feb 2022 13:35:00 +0000 Subject: [PATCH] Memory-map the keymap FD on Wayland to fix EOF error (#278) wlroots based compositors reuse the same FD for keymap, so after a first read is done, the file is seeked to the end and the next read fails, causing the following error: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { kind: UnexpectedEof, message: "failed to fill whole buffer" }' The Wayland documentation says the FD "can be memory-mapped to provide a keyboard mapping description" and then "From version 7 onwards, the fd must be mapped with MAP_PRIVATE by the recipient, as MAP_SHARED may fail." Although it is not very clear, it probably means that the FD must be memory-mapped. --- src/os/posix/wayland.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/os/posix/wayland.rs b/src/os/posix/wayland.rs index 9c2a543..1783d51 100644 --- a/src/os/posix/wayland.rs +++ b/src/os/posix/wayland.rs @@ -30,9 +30,9 @@ use xkb::keymap::Keymap; use std::cell::RefCell; use std::ffi::c_void; use std::fs::File; -use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::io::{self, Seek, SeekFrom, Write}; use std::mem; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use std::slice; use std::sync::mpsc; @@ -1073,20 +1073,29 @@ impl Window { match keymap { KeymapFormat::XkbV1 => { unsafe { - // Read fd content into Vec - let mut file = File::from_raw_fd(fd); - let mut v = Vec::with_capacity(len as usize); - v.set_len(len as usize); - file.read_exact(&mut v)?; + // The file descriptor must be memory-mapped (with MAP_PRIVATE). + let addr = libc::mmap( + std::ptr::null_mut(), + len as usize, + libc::PROT_READ, + libc::MAP_PRIVATE, + fd, + 0, + ); + if addr == libc::MAP_FAILED { + return Err(std::io::Error::last_os_error()); + } let ctx = xkbcommon_sys::xkb_context_new(0); let kb_map_ptr = xkbcommon_sys::xkb_keymap_new_from_string( ctx, - v.as_ptr() as *const _ as *const std::os::raw::c_char, + addr as *const i8, xkbcommon_sys::xkb_keymap_format::XKB_KEYMAP_FORMAT_TEXT_V1, 0, ); + libc::munmap(addr, len as usize); + // Wrap keymap Ok(Keymap::from_ptr(kb_map_ptr as *mut _ as *mut c_void)) }