From 9f0043f406178b706e650cf28b3710800db8c350 Mon Sep 17 00:00:00 2001 From: Nova Date: Tue, 11 Jun 2024 07:08:41 -0400 Subject: [PATCH] refactor: remove xwayland (we can always just use the old code) --- src/main.rs | 5 - src/wayland/mod.rs | 23 --- src/wayland/xwayland_rootful.rs | 267 ------------------------------- src/wayland/xwayland_rootless.rs | 29 ---- 4 files changed, 324 deletions(-) delete mode 100644 src/wayland/xwayland_rootful.rs delete mode 100644 src/wayland/xwayland_rootless.rs diff --git a/src/main.rs b/src/main.rs index 18c59d2..a56ecb2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,6 @@ use crate::objects::input::mouse_pointer::MousePointer; use crate::objects::input::sk_controller::SkController; use crate::objects::input::sk_hand::SkHand; use crate::objects::play_space::PlaySpace; -use crate::wayland::X_DISPLAY; use self::core::eventloop::EventLoop; use clap::Parser; @@ -402,10 +401,6 @@ fn run_client( if let Some(wayland_socket) = wayland.socket_name.as_ref() { command.env("WAYLAND_DISPLAY", wayland_socket); } - command.env( - "DISPLAY", - format!(":{}", X_DISPLAY.get().cloned().unwrap_or_default()), - ); command.env("GDK_BACKEND", "wayland"); command.env("QT_QPA_PLATFORM", "wayland"); command.env("MOZ_ENABLE_WAYLAND", "1"); diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index f4466d8..b21bca2 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -8,16 +8,6 @@ mod surface; mod drm; mod utils; mod xdg_shell; -#[cfg(feature = "xwayland_rootful")] -pub mod xwayland_rootful; -#[cfg(feature = "xwayland_rootful")] -use self::xwayland_rootful::X11Lock; -#[cfg(feature = "xwayland_rootful")] -use crate::wayland::xwayland_rootful::start_xwayland; -#[cfg(feature = "xwayland_rootless")] -pub mod xwayland_rootless; -#[cfg(feature = "xwayland_rootless")] -use crate::wayland::xwayland_rootless::start_xwayland; use self::{state::WaylandState, surface::CORE_SURFACES}; use crate::{core::task, wayland::state::ClientState}; @@ -48,7 +38,6 @@ use tokio::{ }; use tracing::{debug_span, info, instrument}; -pub static X_DISPLAY: OnceCell = OnceCell::new(); pub static WAYLAND_DISPLAY: OnceCell = OnceCell::new(); struct EGLRawHandles { @@ -96,10 +85,6 @@ pub struct Wayland { renderer: GlesRenderer, output: Output, dmabuf_rx: UnboundedReceiver<(Dmabuf, Option)>, - #[cfg(feature = "xwayland_rootful")] - pub x_lock: X11Lock, - #[cfg(feature = "xwayland_rootless")] - xwayland_join_handle: JoinHandle>, } impl Wayland { pub fn new() -> Result { @@ -129,13 +114,9 @@ impl Wayland { if let Some(socket_name) = &socket_name { let _ = WAYLAND_DISPLAY.set(socket_name.clone()); } - #[cfg(feature = "xwayland_rootful")] - let x_display = start_xwayland(socket.as_raw_fd())?; info!(socket_name, "Wayland active"); let join_handle = Wayland::start_loop(display.clone(), socket, wayland_state)?; - #[cfg(feature = "xwayland_rootless")] - let xwayland_join_handle = task::new(|| "xwayland", start_xwayland(display_handle))?; Ok(Wayland { display, @@ -144,10 +125,6 @@ impl Wayland { renderer, output, dmabuf_rx, - #[cfg(feature = "xwayland_rootful")] - x_lock: x_display, - #[cfg(feature = "xwayland_rootless")] - xwayland_join_handle, }) } diff --git a/src/wayland/xwayland_rootful.rs b/src/wayland/xwayland_rootful.rs deleted file mode 100644 index b17f010..0000000 --- a/src/wayland/xwayland_rootful.rs +++ /dev/null @@ -1,267 +0,0 @@ -use crate::core::{client::get_env, task}; -use crate::STOP_NOTIFIER; -use smithay::reexports::rustix; -use smithay::reexports::rustix::io::{fcntl_setfd, Errno, FdFlags}; -use smithay::reexports::rustix::net::SocketAddrUnix; -use std::io::{Read, Write}; -use std::{ - io::ErrorKind, - os::{ - fd::{AsRawFd, BorrowedFd, RawFd}, - unix::process::CommandExt, - }, - process::{ChildStdout, Command, Stdio}, -}; -use tokio::net::{UnixListener, UnixStream}; -use tokio::task::AbortHandle; -use tracing::{debug, info, warn}; - -use super::X_DISPLAY; - -pub fn start_xwayland(wayland_socket: RawFd) -> std::io::Result { - let (mut lock, listener) = bind_socket()?; - - let abort_handle = task::new(|| "X11 Client Acceptor", async move { - loop { - let Ok((stream, _)) = tokio::select! { - _ = STOP_NOTIFIER.notified() => break, - e = listener.accept() => e, - } else { - continue; - }; - - let Ok((x_wm_x11, _x_wm_me)) = UnixStream::pair() else { - continue; - }; - let Ok(env) = stream - .peer_cred() - .and_then(|c| c.pid().ok_or(ErrorKind::Other.into())) - .and_then(get_env) - else { - continue; - }; - - let _ = spawn_xwayland( - lock.display, - wayland_socket, - x_wm_x11, - stream.as_raw_fd(), - env.get("STARDUST_STARTUP_TOKEN").cloned(), - ); - } - }) - .map_err(|_| ErrorKind::Other)? - .abort_handle(); - lock.x_abort_handle.replace(abort_handle); - let _ = X_DISPLAY.set(lock.display); - Ok(lock) -} - -/// Find a free X11 display slot and setup -pub(crate) fn bind_socket() -> Result<(X11Lock, UnixListener), std::io::Error> { - for d in 0..33 { - // if fails, try the next one - if let Ok(lock) = X11Lock::grab(d) { - // we got a lockfile, try and create the socket - match open_x11_socket_for_display(d) { - Ok(socket) => return Ok((lock, socket)), - Err(err) => warn!(display = d, "Failed to create sockets: {}", err), - } - } - } - // If we reach here, all values from 0 to 32 failed - // we need to stop trying at some point - - Err(std::io::Error::new( - std::io::ErrorKind::AddrInUse, - "Could not find a free socket for the XServer.", - )) -} - -#[derive(Debug)] -pub(crate) struct X11Lock { - display: u32, - x_abort_handle: Option, -} - -impl X11Lock { - /// Try to grab a lockfile for given X display number - fn grab(number: u32) -> Result { - debug!(display = number, "Attempting to aquire an X11 display lock"); - let filename = format!("/tmp/.X{}-lock", number); - let lockfile = ::std::fs::OpenOptions::new() - .write(true) - .create_new(true) - .open(&filename); - match lockfile { - Ok(mut file) => { - // we got it, write our PID in it and we're good - let ret = file.write_fmt(format_args!( - "{:>10}\n", - rustix::process::Pid::as_raw(Some(rustix::process::getpid())) - )); - if ret.is_err() { - // write to the file failed ? we abandon - ::std::mem::drop(file); - let _ = ::std::fs::remove_file(&filename); - Err(()) - } else { - debug!(display = number, "X11 lock acquired"); - // we got the lockfile and wrote our pid to it, all is good - Ok(X11Lock { - display: number, - x_abort_handle: None, - }) - } - } - Err(_) => { - debug!(display = number, "Failed to acquire lock"); - // we could not open the file, now we try to read it - // and if it contains the pid of a process that no longer - // exist (so if a previous x server claimed it and did not - // exit gracefully and remove it), we claim it - // if we can't open it, give up - let mut file = ::std::fs::File::open(&filename).map_err(|_| ())?; - let mut spid = [0u8; 11]; - file.read_exact(&mut spid).map_err(|_| ())?; - ::std::mem::drop(file); - let pid = rustix::process::Pid::from_raw( - ::std::str::from_utf8(&spid) - .map_err(|_| ())? - .trim() - .parse::() - .map_err(|_| ())?, - ) - .ok_or(())?; - if let Err(Errno::SRCH) = rustix::process::test_kill_process(pid) { - // no process whose pid equals the contents of the lockfile exists - // remove the lockfile and try grabbing it again - if let Ok(()) = ::std::fs::remove_file(filename) { - debug!( - display = number, - "Lock was blocked by a defunct X11 server, trying again" - ); - return X11Lock::grab(number); - } else { - // we could not remove the lockfile, abort - return Err(()); - } - } - // if we reach here, this lockfile exists and is probably in use, give up - Err(()) - } - } - } - - pub(crate) fn display(&self) -> u32 { - self.display - } -} - -impl Drop for X11Lock { - fn drop(&mut self) { - info!("Cleaning up X11 lock."); - // Cleanup all the X11 files - if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X11-unix/X{}", self.display)) { - warn!(error = ?e, "Failed to remove X11 socket"); - } - if let Err(e) = ::std::fs::remove_file(format!("/tmp/.X{}-lock", self.display)) { - warn!(error = ?e, "Failed to remove X11 lockfile"); - } - if let Some(join_handle) = self.x_abort_handle.take() { - join_handle.abort(); - } - } -} - -/// Open the two unix sockets an X server listens on -/// -/// Should only be done after the associated lockfile is acquired! -fn open_x11_socket_for_display(display: u32) -> rustix::io::Result { - let path = format!("/tmp/.X11-unix/X{}", display); - let _ = ::std::fs::remove_file(&path); - // We know this path is not too long, these unwrap cannot fail - let fs_addr = SocketAddrUnix::new(path.as_bytes()).unwrap(); - open_socket(fs_addr) -} - -/// Open an unix socket for listening and bind it to given path -fn open_socket(addr: SocketAddrUnix) -> rustix::io::Result { - // create an unix stream socket - let fd = rustix::net::socket_with( - rustix::net::AddressFamily::UNIX, - rustix::net::SocketType::STREAM, - rustix::net::SocketFlags::CLOEXEC, - None, - )?; - // bind it to requested address - rustix::net::bind_unix(&fd, &addr)?; - rustix::net::listen(&fd, 1)?; - Ok(UnixListener::from_std(std::os::unix::net::UnixListener::from(fd)).unwrap()) -} - -fn spawn_xwayland( - display: u32, - wayland_socket: RawFd, - wm_socket: UnixStream, - listen_socket: RawFd, - stardust_startup_token: Option, -) -> std::io::Result { - let mut command = Command::new("sh"); - - // We use output stream to communicate because FD is easier to handle than exit code. - command.stdout(Stdio::piped()); - - let mut xwayland_args = format!(":{} -geometry 1920x1080", display); - xwayland_args.push_str(&format!(" -listenfd {}", listen_socket)); - - // This command let sh to: - // * Set up signal handler for USR1 - // * Launch Xwayland with USR1 ignored so Xwayland will signal us when it is ready (also redirect - // Xwayland's STDOUT to STDERR so its output, if any, won't distract us) - // * Print "S" and exit if USR1 is received - command.arg("-c").arg(format!( - "trap 'echo S' USR1; (trap '' USR1; exec Xwayland {}) 1>&2 & wait", - xwayland_args - )); - - // Setup the environment: clear everything except PATH and XDG_RUNTIME_DIR - command.env_clear(); - for (key, value) in std::env::vars_os() { - if key.to_str() == Some("PATH") || key.to_str() == Some("XDG_RUNTIME_DIR") { - command.env(key, value); - continue; - } - } - command.env("WAYLAND_SOCKET", format!("{}", wayland_socket.as_raw_fd())); - command.env( - "STARDUST_STARTUP_TOKEN", - stardust_startup_token.unwrap_or_default(), - ); - - unsafe { - let wayland_socket_fd = wayland_socket.as_raw_fd(); - let wm_socket_fd = wm_socket.as_raw_fd(); - command.pre_exec(move || { - // unset the CLOEXEC flag from the sockets we need to pass - // to xwayland - unset_cloexec(wayland_socket_fd)?; - unset_cloexec(wm_socket_fd)?; - unset_cloexec(listen_socket)?; - Ok(()) - }); - } - - let mut child = command.spawn()?; - Ok(child.stdout.take().expect("stdout should be piped")) -} - -/// Remove the `O_CLOEXEC` flag from this `Fd` -/// -/// This means that the `Fd` will *not* be automatically -/// closed when we `exec()` into XWayland -unsafe fn unset_cloexec(fd: RawFd) -> std::io::Result<()> { - let fd = BorrowedFd::borrow_raw(fd); - fcntl_setfd(fd, FdFlags::empty())?; - Ok(()) -} diff --git a/src/wayland/xwayland_rootless.rs b/src/wayland/xwayland_rootless.rs deleted file mode 100644 index 00e6a54..0000000 --- a/src/wayland/xwayland_rootless.rs +++ /dev/null @@ -1,29 +0,0 @@ -use color_eyre::eyre::Result; -use smithay::{reexports::wayland_server::DisplayHandle, xwayland::XWayland}; -use std::{process::Stdio, time::Duration}; -use tokio::io::unix::AsyncFd; - -use super::X_DISPLAY; - -pub async fn start_xwayland(dh: DisplayHandle) -> Result<()> { - let (mut xwayland, client) = XWayland::spawn( - &dh, - None, - std::iter::empty::<(String, String)>(), - true, - Stdio::null(), - Stdio::null(), - |_| (), - )?; - - // just wait until it's readable - drop(AsyncFd::new(xwayland.poll_fd())?.readable().await?); - let wm_socket = xwayland.take_socket()?.unwrap(); - - let _ = X_DISPLAY.set(xwayland.display_number()); - - println!("yippeee x is available at :{}", xwayland.display_number()); - - tokio::time::sleep(Duration::from_secs(100000000000)).await; - Ok(()) -}