use { crate::{ client::{Client, ClientError}, leaks::Tracker, object::{Object, Version}, utils::{ clone3::{Forked, fork_with_pidfd}, errorfmt::ErrorFmt, oserror::OsErrorExt, pipe::{Pipe, pipe}, }, wire::{JayReexecId, jay_reexec::*}, }, std::{array::from_mut, cell::RefCell, rc::Rc}, thiserror::Error, uapi::{OwnedFd, UstrPtr, c, close_range, dup2, waitpid}, }; pub struct JayReexec { pub id: JayReexecId, pub client: Rc, pub tracker: Tracker, pub version: Version, pub args: RefCell>, } impl JayReexec { fn send_failed(&self, msg: &str) { self.client.event(Failed { self_id: self.id, msg, }); } fn delay_close_input_fd(&self) -> Option { // It's 2025 and closing evdev fds is still abysmally slow. let mut fds = self.client.state.backend.get().get_input_fds(); if fds.is_empty() { return None; } macro_rules! pipe { () => { match pipe() { Ok(p) => p, Err(e) => { log::error!("Could not create pipe: {}", ErrorFmt(e)); return None; } } }; } let Pipe { read: p1, write: c1, } = pipe!(); let Pipe { read: c2, write: p2, } = pipe!(); if let Ok(f) = fork_with_pidfd(false) { match f { Forked::Parent { pid, .. } => { let _ = waitpid(pid, 0); } Forked::Child { .. } => { if let Ok(f) = fork_with_pidfd(false) && let Forked::Child { .. } = f { drop(p2); fds.sort_by_key(|fd| fd.raw()); let c2_dup = c1.raw().max(c2.raw()).max(fds.last().unwrap().raw()) + 1; let c1_dup = c2_dup + 1; let _ = dup2(c1.raw(), c1_dup); let _ = dup2(c2.raw(), c2_dup); for (idx, fd) in fds.iter().enumerate() { let _ = dup2(fd.raw(), idx as _); } let c2_dup_dup = fds.len() as _; let _ = dup2(c2_dup, c2_dup_dup); let _ = close_range(c2_dup_dup as c::c_uint + 1, !0, 0); let mut pollfd = c::pollfd { fd: c2_dup_dup, events: 0, revents: 0, }; let _ = uapi::poll(from_mut(&mut pollfd), -1); } unsafe { c::_exit(0); } } } } drop(c1); let mut pollfd = c::pollfd { fd: p1.raw(), events: 0, revents: 0, }; let _ = uapi::poll(from_mut(&mut pollfd), -1); Some(p2) } } impl JayReexecRequestHandler for JayReexec { type Error = JayReexecError; fn arg(&self, req: Arg<'_>, _slf: &Rc) -> Result<(), Self::Error> { self.args.borrow_mut().push(req.arg.to_owned()); Ok(()) } fn exec(&self, req: Exec<'_>, _slf: &Rc) -> Result<(), Self::Error> { let args = self.args.borrow(); let mut args2 = UstrPtr::new(); args2.push(req.path); for arg in &*args { args2.push(&**arg); } let _drop_after_exec = self.delay_close_input_fd(); if let Err(e) = uapi::execvp(req.path, &args2).to_os_error() { self.send_failed(&e.to_string()); } Ok(()) } } object_base! { self = JayReexec; version = self.version; } impl Object for JayReexec {} simple_add_obj!(JayReexec); #[derive(Debug, Error)] pub enum JayReexecError { #[error(transparent)] ClientError(Box), } efrom!(JayReexecError, ClientError);