From f58a98ddaeac67d064a6d06b31e5d05e9767a108 Mon Sep 17 00:00:00 2001 From: Andrew Phillips Date: Tue, 29 Jul 2025 14:40:30 -0300 Subject: [PATCH] refactor: improve TTY detection using /proc/self/stat and device number parsing Co-authored-by: aider (openai/andrew.openrouter.qwen.qwen3-coder) --- src/meta_plugin/system.rs | 84 ++++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 32 deletions(-) diff --git a/src/meta_plugin/system.rs b/src/meta_plugin/system.rs index 27798e4..a90cdff 100644 --- a/src/meta_plugin/system.rs +++ b/src/meta_plugin/system.rs @@ -373,43 +373,34 @@ impl TtyMetaPlugin { } impl MetaPlugin for TtyMetaPlugin { - fn is_supported(&self) -> bool { - // Check if the 'tty' command is available - std::process::Command::new("sh") - .arg("-c") - .arg("command -v tty") - .output() - .map(|output| output.status.success()) - .unwrap_or(false) - } - fn create(&self) -> Result> { Ok(Box::new(io::sink())) } fn finalize(&mut self) -> io::Result { - // Try to get the TTY from the TTY environment variable first - if let Ok(tty) = env::var("TTY") { - if !tty.is_empty() { - return Ok(tty); - } - } - - // Use the tty command to get the current terminal - match std::process::Command::new("tty").output() { - Ok(output) => { - if output.status.success() { - let tty_path = String::from_utf8_lossy(&output.stdout); - let trimmed = tty_path.trim(); - if trimmed.is_empty() || trimmed == "not a tty" { - Ok("not a tty".to_string()) - } else { - Ok(trimmed.to_string()) + // Try to get TTY from /proc/self/stat + match std::fs::read_to_string("/proc/self/stat") { + Ok(stat_content) => { + // The 7th field (index 6) in /proc/self/stat contains the controlling terminal (TTY) + let fields: Vec<&str> = stat_content.split_whitespace().collect(); + if fields.len() > 6 { + if let Ok(tty_nr) = fields[6].parse::() { + if tty_nr != 0 { + // Convert tty_nr to device path + match self.tty_name(tty_nr) { + Some(tty_name) => return Ok(tty_name), + None => return Ok("unknown tty".to_string()), + } + } } - } else { - Ok("not a tty".to_string()) } } + Err(_) => {} + } + + // Fallback: try to get TTY from /dev/tty + match std::fs::read_link("/dev/tty") { + Ok(path) => Ok(format!("/dev/{}", path.to_string_lossy())), Err(_) => Ok("not a tty".to_string()), } } @@ -421,8 +412,37 @@ impl MetaPlugin for TtyMetaPlugin { fn meta_name(&mut self) -> String { self.meta_name.clone() } - - fn program_info(&self) -> Option<(&str, Vec<&str>)> { - Some(("tty", vec![])) +} + +impl TtyMetaPlugin { + // Convert tty device number to device name + fn tty_name(&self, tty_nr: u32) -> Option { + let major = (tty_nr >> 8) as u16; + let minor = (tty_nr & 0xff) as u16; + + // Handle common TTY device types + match major { + 4 => { + // TTY devices + if minor < 64 { + Some(format!("/dev/tty{}", minor)) + } else { + None + } + }, + 136..=143 => { + // PTS devices + Some(format!("/dev/pts/{}", minor)) + }, + 3 => { + // TTY devices + if minor < 64 { + Some(format!("/dev/tty{}", minor)) + } else { + None + } + }, + _ => None, + } } }