aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2023-08-06 18:30:40 -0400
committerJesse Luehrs <doy@tozt.net>2023-08-06 18:30:40 -0400
commit54e8bf4f2e91407be2054cd38fea81ba830303fd (patch)
tree2ee35f81282d8af91450969f89b42623fd11ec3d
parentdb967551c7d7ee4f38b4fb6ee8d4dd998ad9c871 (diff)
downloadpty-process-54e8bf4f2e91407be2054cd38fea81ba830303fd.tar.gz
pty-process-54e8bf4f2e91407be2054cd38fea81ba830303fd.zip
convert to rustix
it seems more maintained, and hopefully this will fix compile issues on macos
-rw-r--r--Cargo.toml3
-rw-r--r--deny.toml8
-rw-r--r--src/blocking/pty.rs12
-rw-r--r--src/error.rs12
-rw-r--r--src/pty.rs18
-rw-r--r--src/sys.rs119
-rw-r--r--src/types.rs2
7 files changed, 102 insertions, 72 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 25e2693..f6c4e07 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,12 +14,13 @@ include = ["src/**/*", "LICENSE", "README.md", "CHANGELOG.md"]
[dependencies]
libc = "0.2.147"
-nix = "0.26.2"
+rustix = { version = "0.38.7", features = ["pty", "process", "fs"] }
tokio = { version = "1.29.1", features = ["fs", "process", "net"], optional = true }
[dev-dependencies]
futures = "0.3.28"
+nix = { version = "0.26.2", default-features = false, features = ["signal", "fs", "term", "poll"] }
regex = "1.9.3"
tokio = { version = "1.29.1", features = ["full"] }
diff --git a/deny.toml b/deny.toml
index 2f0b764..1ac6f74 100644
--- a/deny.toml
+++ b/deny.toml
@@ -10,6 +10,14 @@ yanked = "deny"
unsound = "deny"
[bans]
+multiple-versions = "deny"
+wildcards = "deny"
+
+skip = [
+ # this is only a dev dependency (between nix and rustix)
+ { name = "bitflags", version = "1.3.2" },
+ { name = "bitflags", version = "2.3.3" },
+]
[licenses]
allow = ["MIT", "Apache-2.0", "Unicode-DFS-2016"]
diff --git a/src/blocking/pty.rs b/src/blocking/pty.rs
index 445f102..fab88a2 100644
--- a/src/blocking/pty.rs
+++ b/src/blocking/pty.rs
@@ -44,33 +44,33 @@ impl std::os::fd::AsFd for Pty {
impl std::io::Read for Pty {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- self.0 .0.read(buf)
+ self.0.read(buf)
}
}
impl std::io::Write for Pty {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- self.0 .0.write(buf)
+ self.0.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
- self.0 .0.flush()
+ self.0.flush()
}
}
impl std::io::Read for &Pty {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
- (&self.0 .0).read(buf)
+ (&self.0).read(buf)
}
}
impl std::io::Write for &Pty {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
- (&self.0 .0).write(buf)
+ (&self.0).write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
- (&self.0 .0).flush()
+ (&self.0).flush()
}
}
diff --git a/src/error.rs b/src/error.rs
index 8ed24e2..df515c3 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -4,7 +4,7 @@ pub enum Error {
/// error came from std::io::Error
Io(std::io::Error),
/// error came from nix::Error
- Nix(nix::Error),
+ Rustix(rustix::io::Errno),
/// unsplit was called on halves of two different ptys
#[cfg(feature = "async")]
Unsplit(crate::OwnedReadPty, crate::OwnedWritePty),
@@ -14,7 +14,7 @@ impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Io(e) => write!(f, "{e}"),
- Self::Nix(e) => write!(f, "{e}"),
+ Self::Rustix(e) => write!(f, "{e}"),
#[cfg(feature = "async")]
Self::Unsplit(..) => {
write!(f, "unsplit called on halves of two different ptys")
@@ -29,9 +29,9 @@ impl std::convert::From<std::io::Error> for Error {
}
}
-impl std::convert::From<nix::Error> for Error {
- fn from(e: nix::Error) -> Self {
- Self::Nix(e)
+impl std::convert::From<rustix::io::Errno> for Error {
+ fn from(e: rustix::io::Errno) -> Self {
+ Self::Rustix(e)
}
}
@@ -39,7 +39,7 @@ impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
- Self::Nix(e) => Some(e),
+ Self::Rustix(e) => Some(e),
#[cfg(feature = "async")]
Self::Unsplit(..) => None,
}
diff --git a/src/pty.rs b/src/pty.rs
index 87ec874..5b6bd03 100644
--- a/src/pty.rs
+++ b/src/pty.rs
@@ -85,7 +85,7 @@ impl tokio::io::AsyncRead for Pty {
// XXX should be able to optimize this once read_buf is stabilized
// in std
let b = buf.initialize_unfilled();
- match guard.try_io(|inner| (&inner.get_ref().0).read(b)) {
+ match guard.try_io(|inner| inner.get_ref().read(b)) {
Ok(Ok(bytes)) => {
buf.advance(bytes);
return std::task::Poll::Ready(Ok(()));
@@ -108,7 +108,7 @@ impl tokio::io::AsyncWrite for Pty {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).write(buf)) {
+ match guard.try_io(|inner| inner.get_ref().write(buf)) {
Ok(result) => return std::task::Poll::Ready(result),
Err(_would_block) => continue,
}
@@ -124,7 +124,7 @@ impl tokio::io::AsyncWrite for Pty {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).flush()) {
+ match guard.try_io(|inner| inner.get_ref().flush()) {
Ok(_) => return std::task::Poll::Ready(Ok(())),
Err(_would_block) => continue,
}
@@ -161,7 +161,7 @@ impl<'a> tokio::io::AsyncRead for ReadPty<'a> {
// XXX should be able to optimize this once read_buf is stabilized
// in std
let b = buf.initialize_unfilled();
- match guard.try_io(|inner| (&inner.get_ref().0).read(b)) {
+ match guard.try_io(|inner| inner.get_ref().read(b)) {
Ok(Ok(bytes)) => {
buf.advance(bytes);
return std::task::Poll::Ready(Ok(()));
@@ -197,7 +197,7 @@ impl<'a> tokio::io::AsyncWrite for WritePty<'a> {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).write(buf)) {
+ match guard.try_io(|inner| inner.get_ref().write(buf)) {
Ok(result) => return std::task::Poll::Ready(result),
Err(_would_block) => continue,
}
@@ -213,7 +213,7 @@ impl<'a> tokio::io::AsyncWrite for WritePty<'a> {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).flush()) {
+ match guard.try_io(|inner| inner.get_ref().flush()) {
Ok(_) => return std::task::Poll::Ready(Ok(())),
Err(_would_block) => continue,
}
@@ -272,7 +272,7 @@ impl tokio::io::AsyncRead for OwnedReadPty {
// XXX should be able to optimize this once read_buf is stabilized
// in std
let b = buf.initialize_unfilled();
- match guard.try_io(|inner| (&inner.get_ref().0).read(b)) {
+ match guard.try_io(|inner| inner.get_ref().read(b)) {
Ok(Ok(bytes)) => {
buf.advance(bytes);
return std::task::Poll::Ready(Ok(()));
@@ -309,7 +309,7 @@ impl tokio::io::AsyncWrite for OwnedWritePty {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).write(buf)) {
+ match guard.try_io(|inner| inner.get_ref().write(buf)) {
Ok(result) => return std::task::Poll::Ready(result),
Err(_would_block) => continue,
}
@@ -325,7 +325,7 @@ impl tokio::io::AsyncWrite for OwnedWritePty {
std::task::Poll::Ready(guard) => guard,
std::task::Poll::Pending => return std::task::Poll::Pending,
}?;
- match guard.try_io(|inner| (&inner.get_ref().0).flush()) {
+ match guard.try_io(|inner| inner.get_ref().flush()) {
Ok(_) => return std::task::Poll::Ready(Ok(())),
Err(_would_block) => continue,
}
diff --git a/src/sys.rs b/src/sys.rs
index 60c61e9..878a374 100644
--- a/src/sys.rs
+++ b/src/sys.rs
@@ -1,58 +1,60 @@
-use std::os::fd::{AsRawFd as _, FromRawFd as _};
+use std::os::{
+ fd::{AsRawFd as _, FromRawFd as _},
+ unix::prelude::OsStrExt as _,
+};
#[derive(Debug)]
-pub struct Pty(pub nix::pty::PtyMaster);
+pub struct Pty(std::os::fd::OwnedFd);
impl Pty {
pub fn open() -> crate::Result<Self> {
- let pt = nix::pty::posix_openpt(
- nix::fcntl::OFlag::O_RDWR
- | nix::fcntl::OFlag::O_NOCTTY
- | nix::fcntl::OFlag::O_CLOEXEC,
+ let pt = rustix::pty::openpt(
+ rustix::pty::OpenptFlags::RDWR
+ | rustix::pty::OpenptFlags::NOCTTY
+ | rustix::pty::OpenptFlags::CLOEXEC,
)?;
- nix::pty::grantpt(&pt)?;
- nix::pty::unlockpt(&pt)?;
+ rustix::pty::grantpt(&pt)?;
+ rustix::pty::unlockpt(&pt)?;
Ok(Self(pt))
}
pub fn set_term_size(&self, size: crate::Size) -> crate::Result<()> {
- let size = size.into();
+ let size: libc::winsize = size.into();
let fd = self.0.as_raw_fd();
-
- // Safety: nix::pty::PtyMaster is required to contain a valid file
- // descriptor and size is guaranteed to be initialized because it's a
- // normal rust value, and nix::pty::Winsize is a repr(C) struct with
- // the same layout as `struct winsize` from sys/ioctl.h.
- Ok(unsafe {
- set_term_size_unsafe(fd, std::ptr::NonNull::from(&size).as_ptr())
+ // TODO: upstream this to rustix
+ unsafe {
+ let ret = libc::ioctl(
+ fd,
+ libc::TIOCSWINSZ,
+ std::ptr::NonNull::from(&size).as_ptr(),
+ );
+ if ret == -1 {
+ Err(rustix::io::Errno::from_raw_os_error(
+ *libc::__errno_location(),
+ )
+ .into())
+ } else {
+ Ok(())
+ }
}
- .map(|_| ())?)
}
pub fn pts(&self) -> crate::Result<Pts> {
Ok(Pts(std::fs::OpenOptions::new()
.read(true)
.write(true)
- .open(nix::pty::ptsname_r(&self.0)?)?
+ .open(std::ffi::OsStr::from_bytes(
+ rustix::pty::ptsname(&self.0, vec![])?.as_bytes(),
+ ))?
.into()))
}
#[cfg(feature = "async")]
- pub fn set_nonblocking(&self) -> nix::Result<()> {
- let bits = nix::fcntl::fcntl(
- self.0.as_raw_fd(),
- nix::fcntl::FcntlArg::F_GETFL,
- )?;
- // Safety: bits was just returned from a F_GETFL call. ideally i would
- // just be able to use from_bits here, but it fails for some reason?
- let mut opts =
- unsafe { nix::fcntl::OFlag::from_bits_unchecked(bits) };
- opts |= nix::fcntl::OFlag::O_NONBLOCK;
- nix::fcntl::fcntl(
- self.0.as_raw_fd(),
- nix::fcntl::FcntlArg::F_SETFL(opts),
- )?;
+ pub fn set_nonblocking(&self) -> rustix::io::Result<()> {
+ let mut opts = rustix::fs::fcntl_getfl(&self.0)?;
+ opts |= rustix::fs::OFlags::NONBLOCK;
+ rustix::fs::fcntl_setfl(&self.0, opts)?;
Ok(())
}
@@ -87,6 +89,38 @@ impl std::os::fd::AsRawFd for Pty {
}
}
+impl std::io::Read for Pty {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ rustix::io::read(&self.0, buf).map_err(std::io::Error::from)
+ }
+}
+
+impl std::io::Write for Pty {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ rustix::io::write(&self.0, buf).map_err(std::io::Error::from)
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
+impl std::io::Read for &Pty {
+ fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
+ rustix::io::read(&self.0, buf).map_err(std::io::Error::from)
+ }
+}
+
+impl std::io::Write for &Pty {
+ fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
+ rustix::io::write(&self.0, buf).map_err(std::io::Error::from)
+ }
+
+ fn flush(&mut self) -> std::io::Result<()> {
+ Ok(())
+ }
+}
+
pub struct Pts(std::os::fd::OwnedFd);
impl Pts {
@@ -107,11 +141,10 @@ impl Pts {
pub fn session_leader(&self) -> impl FnMut() -> std::io::Result<()> {
let pts_fd = self.0.as_raw_fd();
move || {
- nix::unistd::setsid()?;
- // Safety: OwnedFds are required to contain a valid file descriptor
- unsafe {
- set_controlling_terminal_unsafe(pts_fd, std::ptr::null())
- }?;
+ rustix::process::setsid()?;
+ rustix::process::ioctl_tiocsctty(unsafe {
+ std::os::fd::BorrowedFd::borrow_raw(pts_fd)
+ })?;
Ok(())
}
}
@@ -134,15 +167,3 @@ impl std::os::fd::AsRawFd for Pts {
self.0.as_raw_fd()
}
}
-
-nix::ioctl_write_ptr_bad!(
- set_term_size_unsafe,
- libc::TIOCSWINSZ,
- nix::pty::Winsize
-);
-
-nix::ioctl_write_ptr_bad!(
- set_controlling_terminal_unsafe,
- libc::TIOCSCTTY,
- libc::c_int
-);
diff --git a/src/types.rs b/src/types.rs
index dd432eb..f9fd3db 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -38,7 +38,7 @@ impl Size {
}
}
-impl From<Size> for nix::pty::Winsize {
+impl From<Size> for libc::winsize {
fn from(size: Size) -> Self {
Self {
ws_row: size.row,