diff options
author | Jesse Luehrs <doy@tozt.net> | 2021-02-23 00:17:01 -0500 |
---|---|---|
committer | Jesse Luehrs <doy@tozt.net> | 2021-02-23 00:17:01 -0500 |
commit | f3e8046eff473aa9bf940b7fbd156cf3dfbfa352 (patch) | |
tree | a6b3ed53e89556cd801a49a0619ba37e4c397be6 | |
parent | acb3681ee251599af194c8555344edc65750ef14 (diff) | |
download | pty-process-f3e8046eff473aa9bf940b7fbd156cf3dfbfa352.tar.gz pty-process-f3e8046eff473aa9bf940b7fbd156cf3dfbfa352.zip |
also create separate pty structs per backend
for now, they are identical, but i will change them to be specialized
next
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | examples/basic.rs | 2 | ||||
-rw-r--r-- | src/async_std.rs | 2 | ||||
-rw-r--r-- | src/command.rs | 41 | ||||
-rw-r--r-- | src/command/async_process.rs | 1 | ||||
-rw-r--r-- | src/command/std.rs | 1 | ||||
-rw-r--r-- | src/command/tokio.rs | 1 | ||||
-rw-r--r-- | src/lib.rs | 9 | ||||
-rw-r--r-- | src/pty.rs | 74 | ||||
-rw-r--r-- | src/pty/async_io.rs | 36 | ||||
-rw-r--r-- | src/pty/std.rs | 36 | ||||
-rw-r--r-- | src/pty/tokio.rs | 36 | ||||
-rw-r--r-- | src/std.rs | 2 | ||||
-rw-r--r-- | src/tokio.rs | 2 |
14 files changed, 184 insertions, 61 deletions
@@ -9,6 +9,7 @@ libc = "*" nix = "0.17" thiserror = "1.0" +async-io = { version = "1.3", optional = true } async-process = { version = "1.0", optional = true } tokio = { version = "1.2", optional = true, features = ["process"] } @@ -16,3 +17,4 @@ tokio = { version = "1.2", optional = true, features = ["process"] } default = ["std"] std = [] +async-std = ["async-io", "async-process"] diff --git a/examples/basic.rs b/examples/basic.rs index d7f99d0..bc9389c 100644 --- a/examples/basic.rs +++ b/examples/basic.rs @@ -35,7 +35,7 @@ impl Drop for RawGuard { } } -fn run(child: &pty_process::Child<std::process::Child>) { +fn run(child: &pty_process::std::Child) { let _raw = RawGuard::new(); let mut buf = [0_u8; 4096]; let pty = child.pty().as_raw_fd(); diff --git a/src/async_std.rs b/src/async_std.rs new file mode 100644 index 0000000..e91a18d --- /dev/null +++ b/src/async_std.rs @@ -0,0 +1,2 @@ +pub type Child = + crate::command::Child<async_process::Child, crate::pty::async_io::Pty>; diff --git a/src/command.rs b/src/command.rs index 0b53626..4679579 100644 --- a/src/command.rs +++ b/src/command.rs @@ -1,34 +1,38 @@ use crate::error::*; +use crate::pty::Pty as _; use ::std::os::unix::io::AsRawFd as _; mod std; -#[cfg(feature = "async-process")] +#[cfg(feature = "async-std")] mod async_process; #[cfg(feature = "tokio")] mod tokio; pub trait Command { type Child; + type Pty; fn spawn_pty( &mut self, size: Option<&crate::pty::Size>, - ) -> Result<Child<Self::Child>>; + ) -> Result<Child<Self::Child, Self::Pty>>; } impl<T> Command for T where T: CommandImpl, + T::Pty: crate::pty::Pty, { type Child = T::Child; + type Pty = T::Pty; fn spawn_pty( &mut self, size: Option<&crate::pty::Size>, - ) -> Result<Child<Self::Child>> { - let (pty, pts, stdin, stdout, stderr) = setup_pty(size)?; + ) -> Result<Child<Self::Child, Self::Pty>> { + let (pty, pts, stdin, stdout, stderr) = setup_pty::<Self::Pty>(size)?; let pt_fd = pty.pt().as_raw_fd(); let pts_fd = pts.as_raw_fd(); @@ -69,12 +73,15 @@ where } } -pub struct Child<T> { - child: T, - pty: crate::pty::Pty, +pub struct Child<C, P> { + child: C, + pty: P, } -impl<T> Child<T> { +impl<C, P> Child<C, P> +where + P: crate::pty::Pty, +{ pub fn pty(&self) -> &::std::fs::File { self.pty.pt() } @@ -84,15 +91,15 @@ impl<T> Child<T> { } } -impl<T> ::std::ops::Deref for Child<T> { - type Target = T; +impl<C, P> ::std::ops::Deref for Child<C, P> { + type Target = C; fn deref(&self) -> &Self::Target { &self.child } } -impl<T> ::std::ops::DerefMut for Child<T> { +impl<C, P> ::std::ops::DerefMut for Child<C, P> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.child } @@ -101,6 +108,7 @@ impl<T> ::std::ops::DerefMut for Child<T> { // XXX shouldn't be pub? pub trait CommandImpl { type Child; + type Pty; fn std_fds( &mut self, @@ -114,16 +122,19 @@ pub trait CommandImpl { fn spawn_impl(&mut self) -> ::std::io::Result<Self::Child>; } -fn setup_pty( +fn setup_pty<P>( size: Option<&crate::pty::Size>, ) -> Result<( - crate::pty::Pty, + P, ::std::fs::File, ::std::os::unix::io::RawFd, ::std::os::unix::io::RawFd, ::std::os::unix::io::RawFd, -)> { - let pty = crate::pty::Pty::new()?; +)> +where + P: crate::pty::Pty, +{ + let pty = P::new()?; if let Some(size) = size { pty.resize(size)?; } diff --git a/src/command/async_process.rs b/src/command/async_process.rs index 4c453e6..4248402 100644 --- a/src/command/async_process.rs +++ b/src/command/async_process.rs @@ -3,6 +3,7 @@ use std::os::unix::io::FromRawFd as _; impl super::CommandImpl for async_process::Command { type Child = async_process::Child; + type Pty = crate::pty::async_io::Pty; fn std_fds( &mut self, diff --git a/src/command/std.rs b/src/command/std.rs index 3287834..f1c5418 100644 --- a/src/command/std.rs +++ b/src/command/std.rs @@ -3,6 +3,7 @@ use std::os::unix::process::CommandExt as _; impl super::CommandImpl for std::process::Command { type Child = std::process::Child; + type Pty = crate::pty::std::Pty; fn std_fds( &mut self, diff --git a/src/command/tokio.rs b/src/command/tokio.rs index 60dfb56..67baf74 100644 --- a/src/command/tokio.rs +++ b/src/command/tokio.rs @@ -2,6 +2,7 @@ use std::os::unix::io::FromRawFd as _; impl super::CommandImpl for tokio::process::Command { type Child = tokio::process::Child; + type Pty = crate::pty::tokio::Pty; fn std_fds( &mut self, @@ -1,6 +1,13 @@ mod command; -pub use command::{Child, Command}; +pub use command::Command; mod error; pub use error::{Error, Result}; mod pty; pub use pty::{Pty, Size}; + +pub mod std; + +#[cfg(feature = "async-std")] +pub mod async_std; +#[cfg(feature = "tokio")] +pub mod tokio; @@ -1,6 +1,24 @@ use crate::error::*; -use std::os::unix::io::{AsRawFd as _, FromRawFd as _, IntoRawFd as _}; +use ::std::os::unix::io::{AsRawFd as _, IntoRawFd as _}; + +pub mod std; + +#[cfg(feature = "async-std")] +pub mod async_io; +#[cfg(feature = "tokio")] +pub mod tokio; + +pub trait Pty { + fn new() -> Result<Self> + where + Self: Sized; + fn pt(&self) -> &::std::fs::File; + fn pts(&self) -> Result<::std::fs::File>; + fn resize(&self, size: &super::Size) -> Result<()> { + set_term_size(self.pt(), size).map_err(Error::SetTermSize) + } +} pub struct Size { row: u16, @@ -45,51 +63,19 @@ impl From<&Size> for nix::pty::Winsize { } } -pub struct Pty { - pt: std::fs::File, - ptsname: std::path::PathBuf, -} - -impl Pty { - pub fn new() -> Result<Self> { - let pt = nix::pty::posix_openpt( - nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_NOCTTY, - ) - .map_err(Error::CreatePty)?; - nix::pty::grantpt(&pt).map_err(Error::CreatePty)?; - nix::pty::unlockpt(&pt).map_err(Error::CreatePty)?; - - let ptsname = - nix::pty::ptsname_r(&pt).map_err(Error::CreatePty)?.into(); - - let pt_fd = pt.into_raw_fd(); +fn create_pt() -> Result<(::std::os::unix::io::RawFd, ::std::path::PathBuf)> { + let pt = nix::pty::posix_openpt( + nix::fcntl::OFlag::O_RDWR | nix::fcntl::OFlag::O_NOCTTY, + ) + .map_err(Error::CreatePty)?; + nix::pty::grantpt(&pt).map_err(Error::CreatePty)?; + nix::pty::unlockpt(&pt).map_err(Error::CreatePty)?; - // safe because posix_openpt (or the previous functions operating on - // the result) would have returned an Err (causing us to return early) - // if the file descriptor was invalid. additionally, into_raw_fd gives - // up ownership over the file descriptor, allowing the newly created - // File object to take full ownership. - let pt = unsafe { std::fs::File::from_raw_fd(pt_fd) }; + let ptsname = nix::pty::ptsname_r(&pt).map_err(Error::CreatePty)?.into(); - Ok(Self { pt, ptsname }) - } - - pub fn pt(&self) -> &std::fs::File { - &self.pt - } + let pt_fd = pt.into_raw_fd(); - pub fn pts(&self) -> Result<std::fs::File> { - let fh = std::fs::OpenOptions::new() - .read(true) - .write(true) - .open(&self.ptsname) - .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?; - Ok(fh) - } - - pub fn resize(&self, size: &Size) -> Result<()> { - set_term_size(self.pt(), size).map_err(Error::SetTermSize) - } + Ok((pt_fd, ptsname)) } nix::ioctl_write_ptr_bad!( @@ -98,7 +84,7 @@ nix::ioctl_write_ptr_bad!( nix::pty::Winsize ); -fn set_term_size(file: &std::fs::File, size: &Size) -> nix::Result<()> { +fn set_term_size(file: &::std::fs::File, size: &Size) -> nix::Result<()> { let size = size.into(); let fd = file.as_raw_fd(); // safe because std::fs::File is required to contain a valid file diff --git a/src/pty/async_io.rs b/src/pty/async_io.rs new file mode 100644 index 0000000..84097f9 --- /dev/null +++ b/src/pty/async_io.rs @@ -0,0 +1,36 @@ +use crate::error::*; + +use std::os::unix::io::FromRawFd as _; + +pub struct Pty { + pt: std::fs::File, + ptsname: std::path::PathBuf, +} + +impl super::Pty for Pty { + fn new() -> Result<Self> { + let (pt_fd, ptsname) = super::create_pt()?; + + // safe because posix_openpt (or the previous functions operating on + // the result) would have returned an Err (causing us to return early) + // if the file descriptor was invalid. additionally, into_raw_fd gives + // up ownership over the file descriptor, allowing the newly created + // File object to take full ownership. + let pt = unsafe { std::fs::File::from_raw_fd(pt_fd) }; + + Ok(Self { pt, ptsname }) + } + + fn pt(&self) -> &std::fs::File { + &self.pt + } + + fn pts(&self) -> Result<std::fs::File> { + let fh = std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(&self.ptsname) + .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?; + Ok(fh) + } +} diff --git a/src/pty/std.rs b/src/pty/std.rs new file mode 100644 index 0000000..84097f9 --- /dev/null +++ b/src/pty/std.rs @@ -0,0 +1,36 @@ +use crate::error::*; + +use std::os::unix::io::FromRawFd as _; + +pub struct Pty { + pt: std::fs::File, + ptsname: std::path::PathBuf, +} + +impl super::Pty for Pty { + fn new() -> Result<Self> { + let (pt_fd, ptsname) = super::create_pt()?; + + // safe because posix_openpt (or the previous functions operating on + // the result) would have returned an Err (causing us to return early) + // if the file descriptor was invalid. additionally, into_raw_fd gives + // up ownership over the file descriptor, allowing the newly created + // File object to take full ownership. + let pt = unsafe { std::fs::File::from_raw_fd(pt_fd) }; + + Ok(Self { pt, ptsname }) + } + + fn pt(&self) -> &std::fs::File { + &self.pt + } + + fn pts(&self) -> Result<std::fs::File> { + let fh = std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(&self.ptsname) + .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?; + Ok(fh) + } +} diff --git a/src/pty/tokio.rs b/src/pty/tokio.rs new file mode 100644 index 0000000..84097f9 --- /dev/null +++ b/src/pty/tokio.rs @@ -0,0 +1,36 @@ +use crate::error::*; + +use std::os::unix::io::FromRawFd as _; + +pub struct Pty { + pt: std::fs::File, + ptsname: std::path::PathBuf, +} + +impl super::Pty for Pty { + fn new() -> Result<Self> { + let (pt_fd, ptsname) = super::create_pt()?; + + // safe because posix_openpt (or the previous functions operating on + // the result) would have returned an Err (causing us to return early) + // if the file descriptor was invalid. additionally, into_raw_fd gives + // up ownership over the file descriptor, allowing the newly created + // File object to take full ownership. + let pt = unsafe { std::fs::File::from_raw_fd(pt_fd) }; + + Ok(Self { pt, ptsname }) + } + + fn pt(&self) -> &std::fs::File { + &self.pt + } + + fn pts(&self) -> Result<std::fs::File> { + let fh = std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(&self.ptsname) + .map_err(|e| Error::OpenPts(self.ptsname.clone(), e))?; + Ok(fh) + } +} diff --git a/src/std.rs b/src/std.rs new file mode 100644 index 0000000..fa07499 --- /dev/null +++ b/src/std.rs @@ -0,0 +1,2 @@ +pub type Child = + crate::command::Child<std::process::Child, crate::pty::std::Pty>; diff --git a/src/tokio.rs b/src/tokio.rs new file mode 100644 index 0000000..289d659 --- /dev/null +++ b/src/tokio.rs @@ -0,0 +1,2 @@ +pub type Child = + crate::command::Child<tokio::process::Child, crate::pty::tokio::Pty>; |