1
0
Fork 0
forked from wry/wry

forker: unify xwayland and other spawning

This commit is contained in:
Julian Orth 2024-03-06 19:47:52 +01:00
parent 0ee539e625
commit a1ba476e68
3 changed files with 83 additions and 47 deletions

View file

@ -1004,7 +1004,7 @@ impl ConfigProxyHandler {
Some(f) => f, Some(f) => f,
_ => return Err(CphError::NoForker), _ => return Err(CphError::NoForker),
}; };
forker.spawn(prog.to_string(), args, env, None); forker.spawn(prog.to_string(), args, env);
Ok(()) Ok(())
} }

View file

@ -17,6 +17,7 @@ use {
}, },
xwayland, xwayland,
}, },
ahash::AHashMap,
bincode::Options, bincode::Options,
jay_config::_private::bincode_ops, jay_config::_private::bincode_ops,
log::Level, log::Level,
@ -155,30 +156,42 @@ impl ForkerProxy {
wmfd: Rc<OwnedFd>, wmfd: Rc<OwnedFd>,
waylandfd: Rc<OwnedFd>, waylandfd: Rc<OwnedFd>,
) -> Result<(Rc<OwnedFd>, c::pid_t), ForkerError> { ) -> Result<(Rc<OwnedFd>, c::pid_t), ForkerError> {
self.fds let (prog, args) = xwayland::build_args();
.borrow_mut() let env = vec![("WAYLAND_SOCKET".to_string(), "6".to_string())];
.extend([stderr, dfd, listenfd, wmfd, waylandfd]); let fds = vec![
let id = self.next_id.fetch_add(1); (2, stderr),
self.outgoing.push(ServerMessage::Xwayland { id }); (3, dfd),
self.pidfd(id).await (4, listenfd),
(5, wmfd),
(6, waylandfd),
];
let pidfd_id = self.next_id.fetch_add(1);
self.spawn_(prog, args, env, fds, Some(pidfd_id));
self.pidfd(pidfd_id).await
} }
pub fn spawn( pub fn spawn(&self, prog: String, args: Vec<String>, env: Vec<(String, String)>) {
self.spawn_(prog, args, env, vec![], None)
}
fn spawn_(
&self, &self,
prog: String, prog: String,
args: Vec<String>, args: Vec<String>,
env: Vec<(String, String)>, env: Vec<(String, String)>,
stderr: Option<Rc<OwnedFd>>, fds: Vec<(i32, Rc<OwnedFd>)>,
pidfd_id: Option<u32>,
) { ) {
let have_stderr = stderr.is_some(); for (_, fd) in &fds {
if let Some(stderr) = stderr { self.fds.borrow_mut().push(fd.clone());
self.fds.borrow_mut().push(stderr);
} }
let fds = fds.into_iter().map(|(a, _)| a).collect();
self.outgoing.push(ServerMessage::Spawn { self.outgoing.push(ServerMessage::Spawn {
prog, prog,
args, args,
env, env,
stderr: have_stderr, fds,
pidfd_id,
}) })
} }
@ -272,10 +285,8 @@ enum ServerMessage {
prog: String, prog: String,
args: Vec<String>, args: Vec<String>,
env: Vec<(String, String)>, env: Vec<(String, String)>,
stderr: bool, fds: Vec<i32>,
}, pidfd_id: Option<u32>,
Xwayland {
id: u32,
}, },
} }
@ -372,9 +383,9 @@ impl Forker {
prog, prog,
args, args,
env, env,
stderr, fds,
} => self.handle_spawn(prog, args, env, stderr, io), pidfd_id,
ServerMessage::Xwayland { id } => self.handle_xwayland(io, id), } => self.handle_spawn(prog, args, env, fds, io, pidfd_id),
} }
} }
@ -386,32 +397,20 @@ impl Forker {
} }
} }
fn handle_xwayland(self: &Rc<Self>, io: &mut IoIn, id: u32) {
let stderr = io.pop_fd();
let fds = vec![
Rc::try_unwrap(io.pop_fd().unwrap()).unwrap(),
Rc::try_unwrap(io.pop_fd().unwrap()).unwrap(),
Rc::try_unwrap(io.pop_fd().unwrap()).unwrap(),
Rc::try_unwrap(io.pop_fd().unwrap()).unwrap(),
];
let (prog, args) = xwayland::build_args(&fds);
let env = vec![("WAYLAND_SOCKET".to_string(), fds[3].raw().to_string())];
self.spawn(prog, args, env, stderr, fds, Some(id));
}
fn handle_spawn( fn handle_spawn(
self: &Rc<Self>, self: &Rc<Self>,
prog: String, prog: String,
args: Vec<String>, args: Vec<String>,
env: Vec<(String, String)>, env: Vec<(String, String)>,
stderr: bool, fds: Vec<i32>,
io: &mut IoIn, io: &mut IoIn,
pidfd_id: Option<u32>,
) { ) {
let stderr = match stderr { let fds = fds
true => io.pop_fd(), .into_iter()
_ => None, .map(|a| (a, Rc::try_unwrap(io.pop_fd().unwrap()).unwrap()))
}; .collect();
self.spawn(prog, args, env, stderr, vec![], None) self.spawn(prog, args, env, fds, pidfd_id)
} }
fn spawn( fn spawn(
@ -419,8 +418,7 @@ impl Forker {
prog: String, prog: String,
args: Vec<String>, args: Vec<String>,
env: Vec<(String, String)>, env: Vec<(String, String)>,
stderr: Option<Rc<OwnedFd>>, fds: Vec<(i32, OwnedFd)>,
fds: Vec<OwnedFd>,
pidfd_id: Option<u32>, pidfd_id: Option<u32>,
) { ) {
let (read, mut write) = pipe2(c::O_CLOEXEC).unwrap(); let (read, mut write) = pipe2(c::O_CLOEXEC).unwrap();
@ -476,9 +474,13 @@ impl Forker {
} }
Forked::Child { .. } => { Forked::Child { .. } => {
let err = (|| { let err = (|| {
if let Some(stderr) = stderr { if let Some(max_desired) = fds.iter().map(|v| v.0).max() {
uapi::dup2(stderr.raw(), 2).unwrap(); match uapi::fcntl_dupfd_cloexec(write.raw(), max_desired.wrapping_add(1)) {
Ok(new) => write = new,
Err(e) => return Err(SpawnError::Dupfd(e.into())),
}
} }
let fds = map_fds(fds)?;
for fd in fds { for fd in fds {
let fd = fd.unwrap(); let fd = fd.unwrap();
let res: Result<_, Errno> = (|| { let res: Result<_, Errno> = (|| {
@ -521,6 +523,8 @@ enum SpawnError {
Exec(#[source] crate::utils::oserror::OsError), Exec(#[source] crate::utils::oserror::OsError),
#[error("Could not unset cloexec flag")] #[error("Could not unset cloexec flag")]
Cloexec(#[source] crate::utils::oserror::OsError), Cloexec(#[source] crate::utils::oserror::OsError),
#[error("dupfd faild")]
Dupfd(#[source] crate::utils::oserror::OsError),
} }
fn setup_fds(mut socket: OwnedFd) -> OwnedFd { fn setup_fds(mut socket: OwnedFd) -> OwnedFd {
@ -564,3 +568,35 @@ fn setup_name(name: &str) {
c::prctl(c::PR_SET_NAME, name.as_ptr()); c::prctl(c::PR_SET_NAME, name.as_ptr());
} }
} }
fn map_fds(fds: Vec<(i32, OwnedFd)>) -> Result<Vec<OwnedFd>, SpawnError> {
let mut desired: Vec<_> = fds.iter().map(|v| v.0).collect();
desired.sort_by(|a, b| b.cmp(a));
let mut existing_to_desired: AHashMap<_, _> = fds.iter().map(|v| (v.1.raw(), v.0)).collect();
let mut desired_to_existing: AHashMap<_, _> = fds.into_iter().map(|v| (v.0, v.1)).collect();
for desired in desired {
let existing = desired_to_existing.get(&desired).unwrap().raw();
if existing == desired {
continue;
}
if let Some(conflict_desired) = existing_to_desired.get(&desired).copied() {
match uapi::fcntl_dupfd_cloexec(desired, 0) {
Ok(new) => {
existing_to_desired.remove(&desired);
existing_to_desired.insert(new.raw(), conflict_desired);
desired_to_existing.insert(conflict_desired, new);
}
Err(e) => return Err(SpawnError::Dupfd(e.into())),
}
}
match uapi::dup3(existing, desired, c::O_CLOEXEC) {
Ok(_) => {
existing_to_desired.remove(&existing);
existing_to_desired.insert(desired, desired);
desired_to_existing.insert(desired, OwnedFd::new(desired));
}
Err(e) => return Err(SpawnError::Dupfd(e.into())),
}
}
Ok(desired_to_existing.into_values().collect())
}

View file

@ -198,7 +198,7 @@ async fn run(
Ok(()) Ok(())
} }
pub fn build_args(fds: &[OwnedFd]) -> (String, Vec<String>) { pub fn build_args() -> (String, Vec<String>) {
let prog = "Xwayland".to_string(); let prog = "Xwayland".to_string();
let args = vec![ let args = vec![
"-terminate".to_string(), "-terminate".to_string(),
@ -206,11 +206,11 @@ pub fn build_args(fds: &[OwnedFd]) -> (String, Vec<String>) {
"-verbose".to_string(), "-verbose".to_string(),
10.to_string(), 10.to_string(),
"-displayfd".to_string(), "-displayfd".to_string(),
fds[0].raw().to_string(), "3".to_string(),
"-listenfd".to_string(), "-listenfd".to_string(),
fds[1].raw().to_string(), "4".to_string(),
"-wm".to_string(), "-wm".to_string(),
fds[2].raw().to_string(), "5".to_string(),
]; ];
(prog, args) (prog, args)
} }