diff --git a/Cargo.lock b/Cargo.lock index c8b0964d..d7c0c4d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,9 +266,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" [[package]] name = "cbc" @@ -2147,9 +2147,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "df33b2b81ac578cabaf06b89b0631153a3f416b0a886e8a7a1707fb51abbd1ef" dependencies = [ "ring", "rustls-pki-types", diff --git a/src/bin/rbw/actions.rs b/src/bin/rbw/actions.rs index a0a34e8c..2a421d48 100644 --- a/src/bin/rbw/actions.rs +++ b/src/bin/rbw/actions.rs @@ -189,6 +189,40 @@ fn wait_for_exit(pid: rustix::process::Pid) { fn get_environment() -> rbw::protocol::Environment { let tty = std::env::var_os("RBW_TTY").or_else(|| { + // Check if stdin is actually a terminal before attempting to get its path + if !is_terminal::is_terminal(std::io::stdin()) { + return None; + } + + // On macOS, ttyname_r can be extremely slow (taking seconds instead of milliseconds) + // as reported in https://github.com/doy/rbw/issues/11 + // Use fcntl with F_GETPATH instead, which is much faster + #[cfg(target_os = "macos")] + { + use std::os::fd::AsRawFd; + // PATH_MAX is typically 1024 on macOS, use a reasonable constant + const PATH_BUF_SIZE: usize = 1024; + + let fd = std::io::stdin().as_raw_fd(); + let mut buf = [0u8; PATH_BUF_SIZE]; + // F_GETPATH = 50 on macOS - gets the path of a file descriptor + let ret = unsafe { libc::fcntl(fd, 50, buf.as_mut_ptr()) }; + if ret != -1 { + // Find the null terminator + if let Some(len) = buf.iter().position(|&b| b == 0) { + if len > 0 { + let path_bytes = &buf[..len]; + if let Ok(path_str) = std::str::from_utf8(path_bytes) + { + return Some(std::ffi::OsString::from(path_str)); + } + } + } + } + } + + // For non-macOS platforms, or if the macOS-specific approach failed, + // use the standard ttyname approach rustix::termios::ttyname(std::io::stdin(), vec![]) .ok() .map(|p| std::ffi::OsString::from_vec(p.as_bytes().to_vec()))