Accept -listenfd and pass on to Xwayland

This commit is contained in:
Ivan Molodetskikh 2025-06-03 17:33:59 +03:00 committed by Supreeeme
parent ac391db415
commit 9e48795087
3 changed files with 64 additions and 11 deletions

View file

@ -8,7 +8,7 @@ use log::{error, info};
use rustix::event::{poll, PollFd, PollFlags}; use rustix::event::{poll, PollFd, PollFlags};
use smithay_client_toolkit::data_device_manager::WritePipe; use smithay_client_toolkit::data_device_manager::WritePipe;
use std::io::{BufRead, BufReader, Read, Write}; use std::io::{BufRead, BufReader, Read, Write};
use std::os::fd::{AsFd, AsRawFd, BorrowedFd}; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd};
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::process::{Command, ExitStatus, Stdio}; use std::process::{Command, ExitStatus, Stdio};
use wayland_server::{Display, ListeningSocket}; use wayland_server::{Display, ListeningSocket};
@ -35,6 +35,7 @@ type RealServerState = ServerState<RealConnection>;
pub trait RunData { pub trait RunData {
fn display(&self) -> Option<&str>; fn display(&self) -> Option<&str>;
fn listenfds(&mut self) -> Vec<OwnedFd>;
fn server(&self) -> Option<UnixStream> { fn server(&self) -> Option<UnixStream> {
None None
} }
@ -46,7 +47,7 @@ pub trait RunData {
fn xwayland_ready(&self, _display: String, _pid: u32) {} fn xwayland_ready(&self, _display: String, _pid: u32) {}
} }
pub fn main(data: impl RunData) -> Option<()> { pub fn main(mut data: impl RunData) -> Option<()> {
let mut version = env!("VERGEN_GIT_DESCRIBE"); let mut version = env!("VERGEN_GIT_DESCRIBE");
if version == "VERGEN_IDEMPOTENT_OUTPUT" { if version == "VERGEN_IDEMPOTENT_OUTPUT" {
version = env!("CARGO_PKG_VERSION"); version = env!("CARGO_PKG_VERSION");
@ -70,6 +71,12 @@ pub fn main(data: impl RunData) -> Option<()> {
if let Some(display) = data.display() { if let Some(display) = data.display() {
xwayland.arg(display); xwayland.arg(display);
} }
let fds = data.listenfds();
for fd in &fds {
xwayland.args(["-listenfd", &fd.as_raw_fd().to_string()]);
}
let mut xwayland = xwayland let mut xwayland = xwayland
.args([ .args([
"-rootless", "-rootless",
@ -84,6 +91,9 @@ pub fn main(data: impl RunData) -> Option<()> {
.spawn() .spawn()
.unwrap(); .unwrap();
// Now that Xwayland spawned and got the listenfds, we can close them here.
drop(fds);
let xwl_pid = xwayland.id(); let xwl_pid = xwayland.id();
let (mut finish_tx, mut finish_rx) = UnixStream::pair().unwrap(); let (mut finish_tx, mut finish_rx) = UnixStream::pair().unwrap();

View file

@ -1,24 +1,63 @@
use std::os::fd::{FromRawFd, OwnedFd, RawFd};
fn main() { fn main() {
pretty_env_logger::formatted_timed_builder() pretty_env_logger::formatted_timed_builder()
.filter_level(log::LevelFilter::Info) .filter_level(log::LevelFilter::Info)
.parse_default_env() .parse_default_env()
.init(); .init();
xwayland_satellite::main(RealData(get_display())); xwayland_satellite::main(parse_args());
} }
#[repr(transparent)] struct RealData {
struct RealData(Option<String>); display: Option<String>,
listenfds: Vec<OwnedFd>,
}
impl xwayland_satellite::RunData for RealData { impl xwayland_satellite::RunData for RealData {
fn display(&self) -> Option<&str> { fn display(&self) -> Option<&str> {
self.0.as_deref() self.display.as_deref()
}
fn listenfds(&mut self) -> Vec<OwnedFd> {
std::mem::take(&mut self.listenfds)
} }
} }
fn get_display() -> Option<String> { fn parse_args() -> RealData {
let mut data = RealData {
display: None,
listenfds: Vec::new(),
};
let mut args: Vec<_> = std::env::args().collect(); let mut args: Vec<_> = std::env::args().collect();
if args.len() > 2 { if args.len() < 2 {
panic!("Unexpected arguments: {:?}", &args[2..]); return data;
} }
(args.len() == 2).then(|| args.swap_remove(1)) // Argument at index 1 is our display name. The rest can be -listenfd.
let mut i = 2;
while i < args.len() {
let arg = &args[i];
if arg == "-listenfd" {
let next = i + 1;
if next == args.len() {
// Matches the Xwayland error message.
panic!("Required argument to -listenfd not specified");
}
let fd: RawFd = args[next].parse().expect("Error parsing -listenfd number");
// SAFETY:
// - whoever runs the binary must ensure this fd is open and valid.
// - parse_args() must only be called once to avoid double closing.
let fd = unsafe { OwnedFd::from_raw_fd(fd) };
data.listenfds.push(fd);
i += 2;
} else {
panic!("Unrecognized argument: {arg}");
}
}
data.display = Some(args.swap_remove(1));
data
} }

View file

@ -3,7 +3,7 @@ use rustix::process::{Pid, Signal, WaitOptions};
use std::collections::HashMap; use std::collections::HashMap;
use std::io::Write; use std::io::Write;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::os::fd::{AsRawFd, BorrowedFd}; use std::os::fd::{AsRawFd, BorrowedFd, OwnedFd};
use std::os::unix::net::UnixStream; use std::os::unix::net::UnixStream;
use std::sync::{ use std::sync::{
atomic::{AtomicBool, Ordering}, atomic::{AtomicBool, Ordering},
@ -72,6 +72,10 @@ impl xwls::RunData for TestData {
None None
} }
fn listenfds(&mut self) -> Vec<OwnedFd> {
Vec::new()
}
fn server(&self) -> Option<UnixStream> { fn server(&self) -> Option<UnixStream> {
let mut server = self.server.lock().unwrap(); let mut server = self.server.lock().unwrap();
assert!(server.is_some()); assert!(server.is_some());