From 7378dfbc0052dcda076cd3242f29d31eab265566 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 8 Mar 2023 00:39:55 -0500 Subject: use the new fd apis in std --- examples/basic.rs | 4 +-- examples/raw_guard/mod.rs | 2 +- src/blocking/pty.rs | 12 ++++++-- src/pty.rs | 12 ++++++-- src/sys.rs | 78 +++++++++++++++++++++++++++-------------------- tests/behavior.rs | 43 +++++++++++++++----------- tests/pipe.rs | 34 +++++++++++---------- 7 files changed, 109 insertions(+), 76 deletions(-) diff --git a/examples/basic.rs b/examples/basic.rs index db83818..c490008 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -2,7 +2,7 @@ mod raw_guard; mod main { use std::io::{Read as _, Write as _}; - use std::os::unix::io::AsRawFd as _; + use std::os::fd::{AsFd as _, AsRawFd as _}; pub fn run( child: &mut std::process::Child, @@ -10,7 +10,7 @@ mod main { ) { let _raw = super::raw_guard::RawGuard::new(); let mut buf = [0_u8; 4096]; - let pty_fd = pty.as_raw_fd(); + let pty_fd = pty.as_fd().as_raw_fd(); let stdin_fd = std::io::stdin().as_raw_fd(); loop { diff --git a/examples/raw_guard/mod.rs b/examples/raw_guard/mod.rs index cb6a7d6..4ce498b 100644 --- a/examples/raw_guard/mod.rs +++ b/examples/raw_guard/mod.rs @@ -1,4 +1,4 @@ -use std::os::unix::io::AsRawFd as _; +use std::os::fd::AsRawFd as _; pub struct RawGuard { termios: nix::sys::termios::Termios, diff --git a/src/blocking/pty.rs b/src/blocking/pty.rs index e2c5bde..445f102 100644 --- a/src/blocking/pty.rs +++ b/src/blocking/pty.rs @@ -30,9 +30,15 @@ impl Pty { } } -impl std::os::unix::io::AsRawFd for Pty { - fn as_raw_fd(&self) -> std::os::unix::io::RawFd { - self.0 .0.as_raw_fd() +impl From for std::os::fd::OwnedFd { + fn from(pty: Pty) -> Self { + pty.0.into() + } +} + +impl std::os::fd::AsFd for Pty { + fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> { + self.0.as_fd() } } diff --git a/src/pty.rs b/src/pty.rs index 1071df9..87ec874 100644 --- a/src/pty.rs +++ b/src/pty.rs @@ -59,9 +59,15 @@ impl Pty { } } -impl std::os::unix::io::AsRawFd for Pty { - fn as_raw_fd(&self) -> std::os::unix::io::RawFd { - self.0.as_raw_fd() +impl From for std::os::fd::OwnedFd { + fn from(pty: Pty) -> Self { + pty.0.into_inner().into() + } +} + +impl std::os::fd::AsFd for Pty { + fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> { + self.0.get_ref().as_fd() } } diff --git a/src/sys.rs b/src/sys.rs index 272255f..60c61e9 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -1,4 +1,4 @@ -use std::os::unix::io::{AsRawFd as _, FromRawFd as _, IntoRawFd as _}; +use std::os::fd::{AsRawFd as _, FromRawFd as _}; #[derive(Debug)] pub struct Pty(pub nix::pty::PtyMaster); @@ -35,7 +35,7 @@ impl Pty { .read(true) .write(true) .open(nix::pty::ptsname_r(&self.0)?)? - .into_raw_fd())) + .into())) } #[cfg(feature = "async")] @@ -58,43 +58,49 @@ impl Pty { } } -impl std::os::unix::io::AsRawFd for Pty { - fn as_raw_fd(&self) -> std::os::unix::io::RawFd { +impl From for std::os::fd::OwnedFd { + fn from(pty: Pty) -> Self { + let Pty(nix_ptymaster) = pty; + let raw_fd = nix_ptymaster.as_raw_fd(); + std::mem::forget(nix_ptymaster); + + // Safety: nix::pty::PtyMaster is required to contain a valid file + // descriptor, and we ensured that the file descriptor will remain + // valid by skipping the drop implementation for nix::pty::PtyMaster + unsafe { Self::from_raw_fd(raw_fd) } + } +} + +impl std::os::fd::AsFd for Pty { + fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> { + let raw_fd = self.0.as_raw_fd(); + + // Safety: nix::pty::PtyMaster is required to contain a valid file + // descriptor, and it is owned by self + unsafe { std::os::fd::BorrowedFd::borrow_raw(raw_fd) } + } +} + +impl std::os::fd::AsRawFd for Pty { + fn as_raw_fd(&self) -> std::os::fd::RawFd { self.0.as_raw_fd() } } -pub struct Pts(std::os::unix::io::RawFd); +pub struct Pts(std::os::fd::OwnedFd); impl Pts { pub fn setup_subprocess( &self, - ) -> nix::Result<( + ) -> std::io::Result<( std::process::Stdio, std::process::Stdio, std::process::Stdio, )> { - let pts_fd = self.0.as_raw_fd(); - - let stdin = nix::fcntl::fcntl( - pts_fd, - nix::fcntl::FcntlArg::F_DUPFD_CLOEXEC(0), - )?; - let stdout = nix::fcntl::fcntl( - pts_fd, - nix::fcntl::FcntlArg::F_DUPFD_CLOEXEC(0), - )?; - let stderr = nix::fcntl::fcntl( - pts_fd, - nix::fcntl::FcntlArg::F_DUPFD_CLOEXEC(0), - )?; - - // Safety: these file descriptors were all just returned from dup, so - // they must be valid Ok(( - unsafe { std::process::Stdio::from_raw_fd(stdin) }, - unsafe { std::process::Stdio::from_raw_fd(stdout) }, - unsafe { std::process::Stdio::from_raw_fd(stderr) }, + self.0.try_clone()?.into(), + self.0.try_clone()?.into(), + self.0.try_clone()?.into(), )) } @@ -102,7 +108,7 @@ impl Pts { let pts_fd = self.0.as_raw_fd(); move || { nix::unistd::setsid()?; - // Safety: Pts is required to contain a valid file descriptor + // Safety: OwnedFds are required to contain a valid file descriptor unsafe { set_controlling_terminal_unsafe(pts_fd, std::ptr::null()) }?; @@ -111,15 +117,21 @@ impl Pts { } } -impl Drop for Pts { - fn drop(&mut self) { - let _ = nix::unistd::close(self.0); +impl From for std::os::fd::OwnedFd { + fn from(pts: Pts) -> Self { + pts.0 } } -impl std::os::unix::io::AsRawFd for Pts { - fn as_raw_fd(&self) -> std::os::unix::io::RawFd { - self.0 +impl std::os::fd::AsFd for Pts { + fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> { + self.0.as_fd() + } +} + +impl std::os::fd::AsRawFd for Pts { + fn as_raw_fd(&self) -> std::os::fd::RawFd { + self.0.as_raw_fd() } } diff --git a/tests/behavior.rs b/tests/behavior.rs index ee51cb4..8712643 100644 --- a/tests/behavior.rs +++ b/tests/behavior.rs @@ -63,26 +63,24 @@ async fn test_multiple_async() { #[test] fn test_multiple_configured() { use std::io::BufRead as _; - use std::os::unix::io::FromRawFd as _; + use std::os::fd::AsRawFd as _; let pty = pty_process::blocking::Pty::new().unwrap(); let pts = pty.pts().unwrap(); pty.resize(pty_process::Size::new(24, 80)).unwrap(); - let (stderr_pipe_r, stderr_pipe_w) = nix::unistd::pipe().unwrap(); - let mut stderr_pipe_r = std::io::BufReader::new(unsafe { - std::fs::File::from_raw_fd(stderr_pipe_r) - }); - let (pre_exec_pipe_r, pre_exec_pipe_w) = nix::unistd::pipe().unwrap(); - let mut pre_exec_pipe_r = std::io::BufReader::new(unsafe { - std::fs::File::from_raw_fd(pre_exec_pipe_r) - }); + let (stderr_pipe_r, stderr_pipe_w) = pipe(); + let mut stderr_pipe_r = + std::io::BufReader::new(std::fs::File::from(stderr_pipe_r)); + let (pre_exec_pipe_r, pre_exec_pipe_w) = pipe(); + let mut pre_exec_pipe_r = + std::io::BufReader::new(std::fs::File::from(pre_exec_pipe_r)); let mut cmd = pty_process::blocking::Command::new("perl"); cmd.arg("-Esay 'foo'; say STDERR 'foo-stderr'; open my $fh, '>&=3'; say $fh 'foo-3';") - .stderr(unsafe { std::process::Stdio::from_raw_fd(stderr_pipe_w) }); + .stderr(std::process::Stdio::from(stderr_pipe_w)); unsafe { cmd.pre_exec(move || { - nix::unistd::dup2(pre_exec_pipe_w, 3)?; + nix::unistd::dup2(pre_exec_pipe_w.as_raw_fd(), 3)?; nix::fcntl::fcntl( 3, nix::fcntl::F_SETFD(nix::fcntl::FdFlag::empty()), @@ -135,7 +133,7 @@ fn test_multiple_configured() { #[tokio::test] async fn test_multiple_configured_async() { use futures::stream::StreamExt as _; - use std::os::unix::io::FromRawFd as _; + use std::os::fd::{AsRawFd as _, FromRawFd as _, IntoRawFd as _}; use tokio::io::AsyncBufReadExt as _; let mut pty = pty_process::Pty::new().unwrap(); @@ -143,13 +141,13 @@ async fn test_multiple_configured_async() { pty.resize(pty_process::Size::new(24, 80)).unwrap(); let (pty_r, _) = pty.split(); - let (stderr_pipe_r, stderr_pipe_w) = nix::unistd::pipe().unwrap(); + let (stderr_pipe_r, stderr_pipe_w) = pipe(); let mut stderr_pipe_r = tokio::io::BufReader::new(unsafe { - tokio::fs::File::from_raw_fd(stderr_pipe_r) + tokio::fs::File::from_raw_fd(stderr_pipe_r.into_raw_fd()) }); - let (pre_exec_pipe_r, pre_exec_pipe_w) = nix::unistd::pipe().unwrap(); + let (pre_exec_pipe_r, pre_exec_pipe_w) = pipe(); let mut pre_exec_pipe_r = tokio::io::BufReader::new(unsafe { - tokio::fs::File::from_raw_fd(pre_exec_pipe_r) + tokio::fs::File::from_raw_fd(pre_exec_pipe_r.into_raw_fd()) }); let mut cmd = pty_process::Command::new("perl"); cmd.arg( @@ -158,10 +156,10 @@ async fn test_multiple_configured_async() { open my $fh, '>&=3'; \ say $fh 'foo-3';", ) - .stderr(unsafe { std::process::Stdio::from_raw_fd(stderr_pipe_w) }); + .stderr(std::process::Stdio::from(stderr_pipe_w)); unsafe { cmd.pre_exec(move || { - nix::unistd::dup2(pre_exec_pipe_w, 3)?; + nix::unistd::dup2(pre_exec_pipe_w.as_raw_fd(), 3)?; nix::fcntl::fcntl( 3, nix::fcntl::F_SETFD(nix::fcntl::FdFlag::empty()), @@ -304,3 +302,12 @@ async fn test_session_leader_async() { eprintln!("{:?}", status); assert_eq!(status.code().unwrap(), 0); } + +fn pipe() -> (std::os::fd::OwnedFd, std::os::fd::OwnedFd) { + use std::os::fd::FromRawFd as _; + + let (r, w) = nix::unistd::pipe().unwrap(); + (unsafe { std::os::fd::OwnedFd::from_raw_fd(r) }, unsafe { + std::os::fd::OwnedFd::from_raw_fd(w) + }) +} diff --git a/tests/pipe.rs b/tests/pipe.rs index c3d7b9f..3c63602 100644 --- a/tests/pipe.rs +++ b/tests/pipe.rs @@ -1,16 +1,13 @@ #[test] fn test_pipe_basic() { - use std::os::unix::io::FromRawFd as _; - - let (read_fd, write_fd) = - nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + let (read_fd, write_fd) = pipe(); let mut child_from = std::process::Command::new("seq"); child_from.args(["1", "10"]); - child_from.stdout(unsafe { std::process::Stdio::from_raw_fd(write_fd) }); + child_from.stdout(std::process::Stdio::from(write_fd)); let mut child_to = std::process::Command::new("tac"); - child_to.stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); + child_to.stdin(std::process::Stdio::from(read_fd)); child_to.stdout(std::process::Stdio::piped()); assert!(child_from.status().unwrap().success()); @@ -23,23 +20,21 @@ fn test_pipe_basic() { #[test] fn test_pipe_blocking() { use std::io::Read as _; - use std::os::unix::io::FromRawFd as _; - let (read_fd, write_fd) = - nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + let (read_fd, write_fd) = pipe(); let pty_from = pty_process::blocking::Pty::new().unwrap(); let pts_from = pty_from.pts().unwrap(); pty_from.resize(pty_process::Size::new(24, 80)).unwrap(); let mut cmd_from = pty_process::blocking::Command::new("seq"); cmd_from.args(["1", "10"]); - cmd_from.stdout(unsafe { std::process::Stdio::from_raw_fd(write_fd) }); + cmd_from.stdout(std::process::Stdio::from(write_fd)); let mut child_from = cmd_from.spawn(&pts_from).unwrap(); let mut pty_to = pty_process::blocking::Pty::new().unwrap(); let pts_to = pty_to.pts().unwrap(); let mut cmd_to = pty_process::blocking::Command::new("tac"); - cmd_to.stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); + cmd_to.stdin(std::process::Stdio::from(read_fd)); let mut child_to = cmd_to.spawn(&pts_to).unwrap(); assert!(child_from.wait().unwrap().success()); @@ -62,24 +57,22 @@ fn test_pipe_blocking() { #[cfg(feature = "async")] #[tokio::test] async fn test_pipe_async() { - use std::os::unix::io::FromRawFd as _; use tokio::io::AsyncReadExt as _; - let (read_fd, write_fd) = - nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + let (read_fd, write_fd) = pipe(); let pty_from = pty_process::Pty::new().unwrap(); let pts_from = pty_from.pts().unwrap(); pty_from.resize(pty_process::Size::new(24, 80)).unwrap(); let mut cmd_from = pty_process::Command::new("seq"); cmd_from.args(["1", "10"]); - cmd_from.stdout(unsafe { std::process::Stdio::from_raw_fd(write_fd) }); + cmd_from.stdout(std::process::Stdio::from(write_fd)); let mut child_from = cmd_from.spawn(&pts_from).unwrap(); let mut pty_to = pty_process::Pty::new().unwrap(); let pts_to = pty_to.pts().unwrap(); let mut cmd_to = pty_process::Command::new("tac"); - cmd_to.stdin(unsafe { std::process::Stdio::from_raw_fd(read_fd) }); + cmd_to.stdin(std::process::Stdio::from(read_fd)); let mut child_to = cmd_to.spawn(&pts_to).unwrap(); assert!(child_from.wait().await.unwrap().success()); @@ -98,3 +91,12 @@ async fn test_pipe_async() { assert!(child_to.wait().await.unwrap().success()); } + +fn pipe() -> (std::os::fd::OwnedFd, std::os::fd::OwnedFd) { + use std::os::fd::FromRawFd as _; + + let (r, w) = nix::unistd::pipe2(nix::fcntl::OFlag::O_CLOEXEC).unwrap(); + (unsafe { std::os::fd::OwnedFd::from_raw_fd(r) }, unsafe { + std::os::fd::OwnedFd::from_raw_fd(w) + }) +} -- cgit v1.2.3-54-g00ecf