diff --git a/src/cli/idle.rs b/src/cli/idle.rs index a64cdd3d..57a1f38f 100644 --- a/src/cli/idle.rs +++ b/src/cli/idle.rs @@ -7,6 +7,8 @@ use { }, std::{cell::Cell, collections::VecDeque, rc::Rc, str::FromStr}, }; +use crate::utils::stack::Stack; +use crate::wire::WlSurfaceId; pub fn main(global: GlobalArgs, args: IdleArgs) { let tc = ToolClient::new(global.log_level.into()); @@ -40,13 +42,50 @@ impl Idle { jay_idle::Interval::handle(tc, idle, interval.clone(), |iv, msg| { iv.set(msg.interval); }); + struct Inhibitor { + surface: WlSurfaceId, + _client_id: u64, + pid: u64, + comm: String, + } + let inhibitors = Rc::new(Stack::default()); + jay_idle::Inhibitor::handle(tc, idle, inhibitors.clone(), |iv, msg| { + iv.push(Inhibitor { + surface: msg.surface, + _client_id: msg.client_id, + pid: msg.pid, + comm: msg.comm.to_string(), + }); + }); tc.round_trip().await; let minutes = interval.get() / 60; let seconds = interval.get() % 60; + print!("Interval:"); if minutes == 0 && seconds == 0 { - println!("Interval: disabled"); + print!(" disabled"); } else { - println!("Interval: {} minutes {} seconds", minutes, seconds); + if minutes > 0 { + print!(" {} minute", minutes); + if minutes > 1 { + print!("s"); + } + } + if seconds > 0 { + print!(" {} second", seconds); + if seconds > 1 { + print!("s"); + } + } + } + println!(); + let mut inhibitors = inhibitors.take(); + inhibitors.sort_by_key(|i| i.pid); + inhibitors.sort_by_key(|i| i.surface); + if inhibitors.len() > 0{ + println!("Inhibitors:"); + for inhibitor in inhibitors { + println!(" {}, surface {}, pid {}", inhibitor.comm, inhibitor.surface, inhibitor.pid); + } } } diff --git a/src/client.rs b/src/client.rs index c06d7043..5967aca7 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,4 @@ +use bstr::ByteSlice; pub use error::{ClientError, MethodError, ObjectError}; use { crate::{ @@ -28,6 +29,7 @@ use { }, uapi::{c, OwnedFd}, }; +use crate::utils::trim::AsciiTrim; mod error; mod objects; @@ -36,6 +38,12 @@ mod tasks; #[derive(Debug, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)] pub struct ClientId(u64); +impl ClientId { + pub fn raw(self) -> u64 { + self.0 + } +} + impl Display for ClientId { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { Display::fmt(&self.0, f) @@ -128,6 +136,7 @@ impl Clients { secure, last_serial: Cell::new(0), last_enter_serial: Cell::new(0), + pid_info: get_pid_info(uid, pid), }); track!(data, data); let display = Rc::new(WlDisplay::new(&data)); @@ -139,12 +148,13 @@ impl Clients { data: data.clone(), }; log::info!( - "Client {} connected, pid: {}, uid: {}, fd: {}, secure: {}", + "Client {} connected, pid: {}, uid: {}, fd: {}, secure: {}, comm: {:?}", id, pid, uid, client.data.socket.raw(), secure, + data.pid_info.comm, ); self.clients.borrow_mut().insert(client.data.id, client); Ok(data) @@ -212,6 +222,12 @@ pub trait RequestParser<'a>: Debug + Sized { fn parse(parser: &mut MsgParser<'_, 'a>) -> Result; } +pub struct PidInfo { + pub uid: c::uid_t, + pub pid: c::pid_t, + pub comm: String, +} + pub struct Client { pub id: ClientId, pub state: Rc, @@ -227,6 +243,7 @@ pub struct Client { pub secure: bool, pub last_serial: Cell, pub last_enter_serial: Cell, + pub pid_info: PidInfo, } impl Client { @@ -420,3 +437,18 @@ pub trait WaylandObjectLookup: Copy + Into { fn lookup(client: &Client, id: Self) -> Option>; } + +fn get_pid_info(uid: c::uid_t, pid: c::pid_t) -> PidInfo { + let comm = match std::fs::read(format!("/proc/{}/comm", pid)) { + Ok(name) => name.trim().as_bstr().to_string(), + Err(e) => { + log::warn!("Could not read `comm` of pid {}: {}", pid, ErrorFmt(e)); + "Unknown".to_string() + } + }; + PidInfo { + uid, + pid, + comm, + } +} diff --git a/src/forker.rs b/src/forker.rs index e4ea5a0d..b718b221 100644 --- a/src/forker.rs +++ b/src/forker.rs @@ -51,7 +51,7 @@ pub struct ForkerProxy { } struct PidfdHandoff { - pidfd: Cell>>, + pidfd: Cell>>, waiter: Cell>, } @@ -130,7 +130,7 @@ impl ForkerProxy { }) } - async fn pidfd(&self, id: u32) -> Result { + async fn pidfd(&self, id: u32) -> Result<(OwnedFd, c::pid_t), ForkerError> { let handoff = Rc::new(PidfdHandoff { pidfd: Cell::new(None), waiter: Cell::new(None), @@ -154,7 +154,7 @@ impl ForkerProxy { listenfd: Rc, wmfd: Rc, waylandfd: Rc, - ) -> Result { + ) -> Result<(OwnedFd, c::pid_t), ForkerError> { self.fds .borrow_mut() .extend([stderr, dfd, listenfd, wmfd, waylandfd]); @@ -200,13 +200,13 @@ impl ForkerProxy { fn handle_msg(&self, msg: ForkerMessage, io: &mut IoIn) { match msg { ForkerMessage::Log { level, msg } => self.handle_log(level, &msg), - ForkerMessage::PidFd { id, success } => self.handle_pidfd(id, success, io), + ForkerMessage::PidFd { id, success, pid } => self.handle_pidfd(id, success, io, pid), } } - fn handle_pidfd(&self, id: u32, success: bool, io: &mut IoIn) { + fn handle_pidfd(&self, id: u32, success: bool, io: &mut IoIn, pid: c::pid_t) { let res = match success { - true => Ok(io.pop_fd().unwrap()), + true => Ok((io.pop_fd().unwrap(), pid)), _ => Err(ForkerError::PidfdForkFailed), }; if let Some(handoff) = self.pending_pidfds.remove(&id) { @@ -284,7 +284,7 @@ enum ServerMessage { #[derive(Encode, Decode)] enum ForkerMessage { Log { level: usize, msg: String }, - PidFd { id: u32, success: bool }, + PidFd { id: u32, success: bool, pid: c::pid_t }, } struct Forker { @@ -414,7 +414,7 @@ impl Forker { Err(e) => { if let Some(id) = pidfd_id { self.outgoing - .push(ForkerMessage::PidFd { id, success: false }); + .push(ForkerMessage::PidFd { id, success: false, pid: 0 }); } self.outgoing.push(ForkerMessage::Log { level: log::Level::Error as usize, @@ -428,7 +428,7 @@ impl Forker { if let Some(id) = pidfd_id { self.fds.borrow_mut().push(Rc::new(pidfd)); self.outgoing - .push(ForkerMessage::PidFd { id, success: true }); + .push(ForkerMessage::PidFd { id, success: true, pid }); } drop(write); let slf = self.clone(); diff --git a/src/ifs/jay_idle.rs b/src/ifs/jay_idle.rs index d67d68de..695b189a 100644 --- a/src/ifs/jay_idle.rs +++ b/src/ifs/jay_idle.rs @@ -9,6 +9,7 @@ use { std::{rc::Rc, time::Duration}, thiserror::Error, }; +use crate::ifs::wl_surface::zwp_idle_inhibitor_v1::ZwpIdleInhibitorV1; pub struct JayIdle { pub id: JayIdleId, @@ -25,9 +26,26 @@ impl JayIdle { }); } + fn send_inhibitor(&self, surface: &ZwpIdleInhibitorV1) { + let surface = &surface.surface; + self.client.event(Inhibitor { + self_id: self.id, + surface: surface.id, + client_id: surface.client.id.raw(), + pid: surface.client.pid_info.pid as _, + comm: &surface.client.pid_info.comm, + }); + } + fn get_status(&self, parser: MsgParser<'_, '_>) -> Result<(), JayIdleError> { let _req: GetStatus = self.client.parse(self, parser)?; self.send_interval(); + { + let inhibitors = self.client.state.idle.inhibitors.lock(); + for inhibitor in inhibitors.values() { + self.send_inhibitor(inhibitor); + } + } Ok(()) } diff --git a/src/utils/stack.rs b/src/utils/stack.rs index af446435..c74b24cb 100644 --- a/src/utils/stack.rs +++ b/src/utils/stack.rs @@ -1,3 +1,4 @@ +use std::mem; use { crate::utils::ptr_ext::{MutPtrExt, PtrExt}, std::cell::UnsafeCell, @@ -35,4 +36,10 @@ impl Stack { (*v).clone() } } + + pub fn take(&self) -> Vec { + unsafe { + mem::take(self.vec.get().deref_mut()) + } + } } diff --git a/src/xwayland.rs b/src/xwayland.rs index 5b178f21..af43cd32 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -163,14 +163,14 @@ async fn run( Rc::new(client2), ) .await; - let pidfd = match pidfd { + let (pidfd, pid) = match pidfd { Ok(p) => p, Err(e) => return Err(XWaylandError::ExecFailed(e)), }; let client_id = state.clients.id(); let client = state .clients - .spawn2(client_id, state, client1, 9999, 9999, true, true); + .spawn2(client_id, state, client1, uapi::getuid(), pid, true, true); let client = match client { Ok(c) => c, Err(e) => return Err(XWaylandError::SpawnClient(e)), diff --git a/wire/jay_idle.txt b/wire/jay_idle.txt index 3a0098ec..a8a547f4 100644 --- a/wire/jay_idle.txt +++ b/wire/jay_idle.txt @@ -14,5 +14,8 @@ msg interval = 0 { } msg inhibitor = 1 { - name: str, + surface: id(wl_surface), + client_id: pod(u64), + pid: pod(u64), + comm: str, }