diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc133e5e..7b4122bf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - - uses: swatinem/rust-cache@v1 + - uses: swatinem/rust-cache@v2 - name: cargo-check uses: actions-rs/cargo@v1 with: @@ -51,7 +51,7 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - - uses: swatinem/rust-cache@v1 + - uses: swatinem/rust-cache@v2 - name: cargo-test uses: actions-rs/cargo@v1 with: @@ -107,7 +107,7 @@ jobs: with: toolchain: 1.67.0 components: clippy - - uses: swatinem/rust-cache@v1 + - uses: swatinem/rust-cache@v2 - name: cargo-clippy run: cargo clippy --all --all-targets --all-features diff --git a/src/process.rs b/src/process.rs index 4b388bcc..10d99475 100644 --- a/src/process.rs +++ b/src/process.rs @@ -3,6 +3,7 @@ use crate::error::Error; use nix; use nix::fcntl::{open, OFlag}; +use nix::libc::{ioctl, TIOCSCTTY}; use nix::libc::{STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO}; use nix::pty::{grantpt, posix_openpt, unlockpt, PtyMaster}; pub use nix::sys::{signal, wait}; @@ -86,7 +87,7 @@ impl PtyProcess { /// Start a process in a forked pty pub fn new(mut command: Command) -> Result { // Open a new PTY master - let master_fd = posix_openpt(OFlag::O_RDWR)?; + let master_fd = posix_openpt(OFlag::O_RDWR | OFlag::O_NOCTTY)?; // Allow a slave to be generated for it grantpt(&master_fd)?; @@ -112,6 +113,13 @@ impl PtyProcess { dup2(slave_fd, STDOUT_FILENO)?; dup2(slave_fd, STDERR_FILENO)?; + unsafe { + match ioctl(master_fd.as_raw_fd(), TIOCSCTTY) { + 0 => Ok(()), + _ => Err(nix::Error::last()), + }?; + } + // Avoid leaking slave fd if slave_fd > STDERR_FILENO { close(slave_fd)?; @@ -119,9 +127,17 @@ impl PtyProcess { // set echo off let mut flags = termios::tcgetattr(STDIN_FILENO)?; - flags.local_flags &= !termios::LocalFlags::ECHO; + flags.local_flags.remove(termios::LocalFlags::ECHO); termios::tcsetattr(STDIN_FILENO, termios::SetArg::TCSANOW, &flags)?; + loop { + flags = termios::tcgetattr(STDIN_FILENO)?; + if !flags.local_flags.contains(termios::LocalFlags::ECHO) { + break; + } + std::thread::sleep(std::time::Duration::from_millis(100)); + } + command.exec(); Err(Error::Nix(nix::Error::last())) }