From 5b526af7c0d86158bc0bfc7db0e73dea3bc83cfe Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 22 Feb 2021 04:00:53 -0500 Subject: add implementations for async-std and tokio --- Cargo.toml | 8 ++++++++ src/command.rs | 5 +++++ src/command/async_process.rs | 37 +++++++++++++++++++++++++++++++++++++ src/command/tokio.rs | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 86 insertions(+) create mode 100644 src/command/async_process.rs create mode 100644 src/command/tokio.rs diff --git a/Cargo.toml b/Cargo.toml index d1673b2..27e5bf1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,11 @@ edition = "2018" libc = "*" nix = "0.17" thiserror = "1.0" + +async-process = { version = "1.0", optional = true } +tokio = { version = "1.2", optional = true, features = ["process"] } + +[features] +default = ["std"] + +std = [] diff --git a/src/command.rs b/src/command.rs index ba7d764..ca7e4e3 100644 --- a/src/command.rs +++ b/src/command.rs @@ -4,6 +4,11 @@ use ::std::os::unix::io::AsRawFd as _; mod std; +#[cfg(feature = "async-process")] +mod async_process; +#[cfg(feature = "tokio")] +mod tokio; + pub trait Command { fn spawn_pty( &mut self, diff --git a/src/command/async_process.rs b/src/command/async_process.rs new file mode 100644 index 0000000..c712289 --- /dev/null +++ b/src/command/async_process.rs @@ -0,0 +1,37 @@ +use crate::error::*; + +use async_process::unix::CommandExt as _; +use std::os::unix::io::{AsRawFd as _, FromRawFd as _}; + +impl super::Command for async_process::Command { + fn spawn_pty( + &mut self, + size: Option<&crate::pty::Size>, + ) -> Result> { + let (pty, pts, stdin, stdout, stderr) = super::setup_pty(size)?; + + let pt_fd = pty.pt().as_raw_fd(); + let pts_fd = pts.as_raw_fd(); + + // safe because the fds are valid (otherwise pty.pts() or dup() would + // have returned an Err and we would have exited early) and are not + // owned by any other structure (since dup() returns a fresh copy of + // the file descriptor), allowing from_raw_fd to take ownership of it. + self.stdin(unsafe { std::process::Stdio::from_raw_fd(stdin) }) + .stdout(unsafe { std::process::Stdio::from_raw_fd(stdout) }) + .stderr(unsafe { std::process::Stdio::from_raw_fd(stderr) }); + + // safe because setsid() and close() are async-signal-safe functions + // and ioctl() is a raw syscall (which is inherently + // async-signal-safe). + unsafe { + self.pre_exec(move || { + super::pre_exec(pt_fd, pts_fd, stdin, stdout, stderr) + }); + } + + let child = self.spawn().map_err(Error::Spawn)?; + + Ok(super::Child { child, pty }) + } +} diff --git a/src/command/tokio.rs b/src/command/tokio.rs new file mode 100644 index 0000000..f29c247 --- /dev/null +++ b/src/command/tokio.rs @@ -0,0 +1,36 @@ +use crate::error::*; + +use std::os::unix::io::{AsRawFd as _, FromRawFd as _}; + +impl super::Command for tokio::process::Command { + fn spawn_pty( + &mut self, + size: Option<&crate::pty::Size>, + ) -> Result> { + let (pty, pts, stdin, stdout, stderr) = super::setup_pty(size)?; + + let pt_fd = pty.pt().as_raw_fd(); + let pts_fd = pts.as_raw_fd(); + + // safe because the fds are valid (otherwise pty.pts() or dup() would + // have returned an Err and we would have exited early) and are not + // owned by any other structure (since dup() returns a fresh copy of + // the file descriptor), allowing from_raw_fd to take ownership of it. + self.stdin(unsafe { std::process::Stdio::from_raw_fd(stdin) }) + .stdout(unsafe { std::process::Stdio::from_raw_fd(stdout) }) + .stderr(unsafe { std::process::Stdio::from_raw_fd(stderr) }); + + // safe because setsid() and close() are async-signal-safe functions + // and ioctl() is a raw syscall (which is inherently + // async-signal-safe). + unsafe { + self.pre_exec(move || { + super::pre_exec(pt_fd, pts_fd, stdin, stdout, stderr) + }); + } + + let child = self.spawn().map_err(Error::Spawn)?; + + Ok(super::Child { child, pty }) + } +} -- cgit v1.2.3