diff options
Diffstat (limited to 'src/detect/mod.rs')
| -rw-r--r-- | src/detect/mod.rs | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/detect/mod.rs b/src/detect/mod.rs index 408ee669..7d7759d2 100644 --- a/src/detect/mod.rs +++ b/src/detect/mod.rs @@ -366,6 +366,11 @@ pub fn foreground_process_group_id(child_pid: u32) -> Option<u32> { crate::platform::foreground_process_group_id(child_pid) } +/// True when the pane's own shell is at its prompt with nothing running in it. +pub fn pane_shell_is_idle(child_pid: u32) -> bool { + crate::platform::available_pane_shell(child_pid).is_some() +} + fn normalized_process_name(process: &crate::platform::ForegroundProcess) -> String { let effective = process.argv0.as_deref().unwrap_or(&process.name); let lower_effective = effective.to_lowercase(); @@ -1928,6 +1933,49 @@ mod tests { #[cfg(target_os = "linux")] #[test] + fn pane_shell_is_idle_tracks_foreground_command() { + use portable_pty::CommandBuilder; + use std::io::Write; + + fn wait_for(expected: bool, pid: u32) -> bool { + let deadline = std::time::Instant::now() + std::time::Duration::from_secs(5); + while std::time::Instant::now() < deadline { + if pane_shell_is_idle(pid) == expected { + return true; + } + std::thread::sleep(std::time::Duration::from_millis(20)); + } + false + } + + let pair = open_test_pty(); + let mut cmd = CommandBuilder::new("sh"); + cmd.arg("-i"); + cmd.env("ENV", "/dev/null"); + let mut child = pair.slave.spawn_command(cmd).expect("failed to spawn"); + let pid = child.process_id().expect("no pid"); + let mut reader = pair.master.try_clone_reader().expect("no reader"); + std::thread::spawn(move || { + let mut buf = [0u8; 1024]; + while matches!(std::io::Read::read(&mut reader, &mut buf), Ok(n) if n > 0) {} + }); + let mut writer = pair.master.take_writer().expect("no writer"); + + assert!(wait_for(true, pid), "interactive shell should start idle"); + writer.write_all(b"sleep 999\n").unwrap(); + assert!(wait_for(false, pid), "shell running a command is not idle"); + writer.write_all(&[3]).unwrap(); + assert!( + wait_for(true, pid), + "shell should be idle after the command ends" + ); + + child.kill().ok(); + child.wait().ok(); + } + + #[cfg(target_os = "linux")] + #[test] fn proc_stat_parsing_handles_spaces_in_comm() { // Verify our /proc/pid/stat parser correctly extracts fields // even when (comm) could contain spaces. |
