diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0da6dab..ae5ed45 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -48,7 +48,7 @@ jobs: os: [ubuntu-latest, windows-latest] # When updating this, the reminder to update the minimum supported # Rust version in Cargo.toml. - rust: ['1.47'] + rust: ['1.48'] steps: - uses: actions/checkout@v3 - name: Install Rust diff --git a/Cargo.toml b/Cargo.toml index 32aae52..ab27b51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "async-process" version = "1.6.0" authors = ["Stjepan Glavina "] edition = "2018" -rust-version = "1.47" +rust-version = "1.48" description = "Async interface for working with processes" license = "Apache-2.0 OR MIT" repository = "https://github.com/smol-rs/async-process" @@ -25,7 +25,7 @@ autocfg = "1" [target.'cfg(unix)'.dependencies] async-io = "1.8" -libc = "0.2.88" +rustix = { version = "0.36", default-features = false, features = ["std", "fs"] } [target.'cfg(unix)'.dependencies.signal-hook] version = "0.3.0" diff --git a/src/lib.rs b/src/lib.rs index 21efe51..e7b3b51 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -170,7 +170,6 @@ impl Child { (s, r) } - // Called when a child exits. unsafe extern "system" fn callback(_: *mut c_void, _: BOOLEAN) { callback_channel().0.try_send(()).ok(); @@ -485,7 +484,7 @@ impl ChildStdin { Ok(self.0.into_inner().await.into()) } else if #[cfg(unix)] { let child_stdin = self.0.into_inner()?; - blocking_fd(child_stdin.as_raw_fd())?; + blocking_fd(rustix::fd::AsFd::as_fd(&child_stdin))?; Ok(child_stdin.into()) } } @@ -577,7 +576,7 @@ impl ChildStdout { Ok(self.0.into_inner().await.into()) } else if #[cfg(unix)] { let child_stdout = self.0.into_inner()?; - blocking_fd(child_stdout.as_raw_fd())?; + blocking_fd(rustix::fd::AsFd::as_fd(&child_stdout))?; Ok(child_stdout.into()) } } @@ -650,7 +649,7 @@ impl ChildStderr { Ok(self.0.into_inner().await.into()) } else if #[cfg(unix)] { let child_stderr = self.0.into_inner()?; - blocking_fd(child_stderr.as_raw_fd())?; + blocking_fd(rustix::fd::AsFd::as_fd(&child_stderr))?; Ok(child_stderr.into()) } } @@ -1063,22 +1062,24 @@ impl fmt::Debug for Command { /// Moves `Fd` out of non-blocking mode. #[cfg(unix)] -fn blocking_fd(fd: std::os::unix::io::RawFd) -> io::Result<()> { - // Helper macro to execute a system call that returns an `io::Result`. - macro_rules! syscall { - ($fn:ident ( $($arg:expr),* $(,)? ) ) => {{ - let res = unsafe { libc::$fn($($arg, )*) }; - if res == -1 { - return Err(std::io::Error::last_os_error()); - } else { - res +fn blocking_fd(fd: rustix::fd::BorrowedFd<'_>) -> io::Result<()> { + cfg_if::cfg_if! { + // ioctl(FIONBIO) sets the flag atomically, but we use this only on Linux + // for now, as with the standard library, because it seems to behave + // differently depending on the platform. + // https://github.com/rust-lang/rust/commit/efeb42be2837842d1beb47b51bb693c7474aba3d + // https://github.com/libuv/libuv/blob/e9d91fccfc3e5ff772d5da90e1c4a24061198ca0/src/unix/poll.c#L78-L80 + // https://github.com/tokio-rs/mio/commit/0db49f6d5caf54b12176821363d154384357e70a + if #[cfg(target_os = "linux")] { + rustix::io::ioctl_fionbio(fd, false)?; + } else { + let previous = rustix::fs::fcntl_getfl(fd)?; + let new = previous & !rustix::fs::OFlags::NONBLOCK; + if new != previous { + rustix::fs::fcntl_setfl(fd, new)?; } - }}; + } } - - let res = syscall!(fcntl(fd, libc::F_GETFL)); - syscall!(fcntl(fd, libc::F_SETFL, res & !libc::O_NONBLOCK)); - Ok(()) } diff --git a/tests/std.rs b/tests/std.rs index 261c4ba..1c57f1d 100644 --- a/tests/std.rs +++ b/tests/std.rs @@ -308,7 +308,7 @@ fn test_override_env() { let mut cmd = env_cmd(); cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); if let Some(p) = env::var_os("PATH") { - cmd.env("PATH", &p); + cmd.env("PATH", p); } let result = cmd.output().await.unwrap(); let output = String::from_utf8_lossy(&result.stdout).to_string();