mirror of
https://github.com/wez/wezterm.git
synced 2025-01-03 19:21:57 +03:00
filedescriptor: remove anyhow from public interface
Use thiserror instead
This commit is contained in:
parent
ed331542ee
commit
f78190ec9c
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -1234,10 +1234,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "filedescriptor"
|
||||
version = "0.7.3"
|
||||
version = "0.8.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"libc",
|
||||
"thiserror",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "filedescriptor"
|
||||
version = "0.7.3"
|
||||
version = "0.8.0"
|
||||
authors = ["Wez Furlong"]
|
||||
edition = "2018"
|
||||
repository = "https://github.com/wez/wezterm"
|
||||
@ -11,7 +11,7 @@ readme = "README.md"
|
||||
keywords = ["socketpair", "pipe", "poll", "filedescriptor"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
thiserror = "1.0"
|
||||
libc = "0.2"
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
|
@ -14,16 +14,16 @@ the conditional code that would otherwise be required to deal with
|
||||
calling `as_raw_fd` and `as_raw_handle`:
|
||||
|
||||
```
|
||||
use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
|
||||
use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
|
||||
use std::io::Write;
|
||||
|
||||
fn get_stdout() -> anyhow::Result<FileDescriptor> {
|
||||
fn get_stdout() -> Result<FileDescriptor> {
|
||||
let stdout = std::io::stdout();
|
||||
let handle = stdout.lock();
|
||||
FileDescriptor::dup(&handle)
|
||||
}
|
||||
|
||||
fn print_something() -> anyhow::Result<()> {
|
||||
fn print_something() -> Result<()> {
|
||||
get_stdout()?.write(b"hello")?;
|
||||
Ok(())
|
||||
}
|
||||
@ -36,7 +36,6 @@ the lifetime of both the read and write ends of that pipe.
|
||||
```
|
||||
use filedescriptor::Pipe;
|
||||
use std::io::{Read, Write};
|
||||
use anyhow::Error;
|
||||
|
||||
let mut pipe = Pipe::new()?;
|
||||
pipe.write.write(b"hello")?;
|
||||
@ -53,7 +52,6 @@ sockets and functions both on posix and windows systems.
|
||||
|
||||
```
|
||||
use std::io::{Read, Write};
|
||||
use anyhow::Error;
|
||||
|
||||
let (mut a, mut b) = filedescriptor::socketpair()?;
|
||||
a.write(b"hello")?;
|
||||
@ -75,7 +73,6 @@ function is used instead.
|
||||
|
||||
```
|
||||
use filedescriptor::*;
|
||||
use anyhow::Error;
|
||||
use std::time::Duration;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
|
@ -12,16 +12,16 @@
|
||||
//! calling `as_raw_fd` and `as_raw_handle`:
|
||||
//!
|
||||
//! ```
|
||||
//! use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
|
||||
//! use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
|
||||
//! use std::io::Write;
|
||||
//!
|
||||
//! fn get_stdout() -> anyhow::Result<FileDescriptor> {
|
||||
//! fn get_stdout() -> Result<FileDescriptor> {
|
||||
//! let stdout = std::io::stdout();
|
||||
//! let handle = stdout.lock();
|
||||
//! FileDescriptor::dup(&handle)
|
||||
//! }
|
||||
//!
|
||||
//! fn print_something() -> anyhow::Result<()> {
|
||||
//! fn print_something() -> Result<()> {
|
||||
//! get_stdout()?.write(b"hello")?;
|
||||
//! Ok(())
|
||||
//! }
|
||||
@ -32,9 +32,8 @@
|
||||
//! the lifetime of both the read and write ends of that pipe.
|
||||
//!
|
||||
//! ```
|
||||
//! use filedescriptor::Pipe;
|
||||
//! use filedescriptor::{Pipe, Error};
|
||||
//! use std::io::{Read, Write};
|
||||
//! use anyhow::Error;
|
||||
//!
|
||||
//! let mut pipe = Pipe::new()?;
|
||||
//! pipe.write.write(b"hello")?;
|
||||
@ -52,7 +51,7 @@
|
||||
//!
|
||||
//! ```
|
||||
//! use std::io::{Read, Write};
|
||||
//! use anyhow::Error;
|
||||
//! use filedescriptor::Error;
|
||||
//!
|
||||
//! let (mut a, mut b) = filedescriptor::socketpair()?;
|
||||
//! a.write(b"hello")?;
|
||||
@ -75,7 +74,6 @@
|
||||
//!
|
||||
//! ```
|
||||
//! use filedescriptor::*;
|
||||
//! use anyhow::Error;
|
||||
//! use std::time::Duration;
|
||||
//! use std::io::{Read, Write};
|
||||
//!
|
||||
@ -106,6 +104,57 @@ mod windows;
|
||||
#[cfg(windows)]
|
||||
pub use crate::windows::*;
|
||||
|
||||
use thiserror::Error;
|
||||
#[derive(Error, Debug)]
|
||||
#[non_exhaustive]
|
||||
pub enum Error {
|
||||
#[error("failed to create a pipe")]
|
||||
Pipe(#[source] std::io::Error),
|
||||
#[error("failed to create a socketpair")]
|
||||
Socketpair(#[source] std::io::Error),
|
||||
#[error("failed to create a socket")]
|
||||
Socket(#[source] std::io::Error),
|
||||
#[error("failed to bind a socket")]
|
||||
Bind(#[source] std::io::Error),
|
||||
#[error("failed to fetch socket name")]
|
||||
Getsockname(#[source] std::io::Error),
|
||||
#[error("failed to set socket to listen mode")]
|
||||
Listen(#[source] std::io::Error),
|
||||
#[error("failed to connect socket")]
|
||||
Connect(#[source] std::io::Error),
|
||||
#[error("failed to accept socket")]
|
||||
Accept(#[source] std::io::Error),
|
||||
#[error("fcntl read failed")]
|
||||
Fcntl(#[source] std::io::Error),
|
||||
#[error("failed to set cloexec")]
|
||||
Cloexec(#[source] std::io::Error),
|
||||
#[error("failed to change non-blocking mode")]
|
||||
FionBio(#[source] std::io::Error),
|
||||
#[error("poll failed")]
|
||||
Poll(#[source] std::io::Error),
|
||||
#[error("dup of fd {fd} failed")]
|
||||
Dup { fd: i64, source: std::io::Error },
|
||||
#[error("dup of fd {src_fd} to fd {dest_fd} failed")]
|
||||
Dup2 {
|
||||
src_fd: i64,
|
||||
dest_fd: i64,
|
||||
source: std::io::Error,
|
||||
},
|
||||
#[error("Illegal fd value {0}")]
|
||||
IllegalFdValue(i64),
|
||||
#[error("fd value {0} too large to use with select(2)")]
|
||||
FdValueOutsideFdSetSize(i64),
|
||||
#[error("Only socket descriptors can change their non-blocking mode on Windows")]
|
||||
OnlySocketsNonBlocking,
|
||||
#[error("SetStdHandle failed")]
|
||||
SetStdHandle(#[source] std::io::Error),
|
||||
|
||||
#[error("IoError")]
|
||||
Io(#[from] std::io::Error),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// `AsRawFileDescriptor` is a platform independent trait for returning
|
||||
/// a non-owning reference to the underlying platform file descriptor
|
||||
/// type.
|
||||
@ -167,7 +216,7 @@ impl OwnedHandle {
|
||||
/// potentially fallible operation.
|
||||
/// The returned handle has a separate lifetime from the source, but
|
||||
/// references the same object at the kernel level.
|
||||
pub fn try_clone(&self) -> anyhow::Result<Self> {
|
||||
pub fn try_clone(&self) -> Result<Self> {
|
||||
Self::dup_impl(self, self.handle_type)
|
||||
}
|
||||
|
||||
@ -178,7 +227,7 @@ impl OwnedHandle {
|
||||
/// potentially fallible operation.
|
||||
/// The returned handle has a separate lifetime from the source, but
|
||||
/// references the same object at the kernel level.
|
||||
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> anyhow::Result<Self> {
|
||||
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Result<Self> {
|
||||
Self::dup_impl(f, Default::default())
|
||||
}
|
||||
}
|
||||
@ -191,16 +240,16 @@ impl OwnedHandle {
|
||||
/// calling `as_raw_fd` and `as_raw_handle`:
|
||||
///
|
||||
/// ```
|
||||
/// use filedescriptor::{FileDescriptor, FromRawFileDescriptor};
|
||||
/// use filedescriptor::{FileDescriptor, FromRawFileDescriptor, Result};
|
||||
/// use std::io::Write;
|
||||
///
|
||||
/// fn get_stdout() -> anyhow::Result<FileDescriptor> {
|
||||
/// fn get_stdout() -> Result<FileDescriptor> {
|
||||
/// let stdout = std::io::stdout();
|
||||
/// let handle = stdout.lock();
|
||||
/// FileDescriptor::dup(&handle)
|
||||
/// }
|
||||
///
|
||||
/// fn print_something() -> anyhow::Result<()> {
|
||||
/// fn print_something() -> Result<()> {
|
||||
/// get_stdout()?.write(b"hello")?;
|
||||
/// Ok(())
|
||||
/// }
|
||||
@ -233,7 +282,7 @@ impl FileDescriptor {
|
||||
/// potentially fallible operation.
|
||||
/// The returned handle has a separate lifetime from the source, but
|
||||
/// references the same object at the kernel level.
|
||||
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> anyhow::Result<Self> {
|
||||
pub fn dup<F: AsRawFileDescriptor>(f: &F) -> Result<Self> {
|
||||
OwnedHandle::dup(f).map(|handle| Self { handle })
|
||||
}
|
||||
|
||||
@ -243,7 +292,7 @@ impl FileDescriptor {
|
||||
/// potentially fallible operation.
|
||||
/// The returned handle has a separate lifetime from the source, but
|
||||
/// references the same object at the kernel level.
|
||||
pub fn try_clone(&self) -> anyhow::Result<Self> {
|
||||
pub fn try_clone(&self) -> Result<Self> {
|
||||
self.handle.try_clone().map(|handle| Self { handle })
|
||||
}
|
||||
|
||||
@ -251,7 +300,7 @@ impl FileDescriptor {
|
||||
/// to be used for eg: redirecting the stdio streams of a child
|
||||
/// process. The `Stdio` is created using a duplicated handle so
|
||||
/// that the source handle remains alive.
|
||||
pub fn as_stdio(&self) -> anyhow::Result<std::process::Stdio> {
|
||||
pub fn as_stdio(&self) -> Result<std::process::Stdio> {
|
||||
self.as_stdio_impl()
|
||||
}
|
||||
|
||||
@ -261,7 +310,7 @@ impl FileDescriptor {
|
||||
/// non-blocking mode but it will have no effect.
|
||||
/// File descriptors based on sockets are the most portable type
|
||||
/// that can be successfully made non-blocking.
|
||||
pub fn set_non_blocking(&mut self, non_blocking: bool) -> anyhow::Result<()> {
|
||||
pub fn set_non_blocking(&mut self, non_blocking: bool) -> Result<()> {
|
||||
self.set_non_blocking_impl(non_blocking)
|
||||
}
|
||||
|
||||
@ -270,10 +319,7 @@ impl FileDescriptor {
|
||||
/// Since the redirection requires kernel resources that may not be
|
||||
/// available, this is a potentially fallible operation.
|
||||
/// Supports stdin, stdout, and stderr redirections.
|
||||
pub fn redirect_stdio<F: AsRawFileDescriptor>(
|
||||
f: &F,
|
||||
stdio: StdioDescriptor,
|
||||
) -> anyhow::Result<Self> {
|
||||
pub fn redirect_stdio<F: AsRawFileDescriptor>(f: &F, stdio: StdioDescriptor) -> Result<Self> {
|
||||
Self::redirect_stdio_impl(f, stdio)
|
||||
}
|
||||
}
|
||||
@ -282,9 +328,8 @@ impl FileDescriptor {
|
||||
/// connected via a kernel pipe.
|
||||
///
|
||||
/// ```
|
||||
/// use filedescriptor::Pipe;
|
||||
/// use filedescriptor::{Pipe, Error};
|
||||
/// use std::io::{Read,Write};
|
||||
/// use anyhow::Error;
|
||||
///
|
||||
/// let mut pipe = Pipe::new()?;
|
||||
/// pipe.write.write(b"hello")?;
|
||||
@ -331,13 +376,13 @@ use std::time::Duration;
|
||||
///
|
||||
/// The `pfd` array is mutated and the `revents` field is updated to indicate
|
||||
/// which of the events were received.
|
||||
pub fn poll(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
|
||||
pub fn poll(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
|
||||
poll_impl(pfd, duration)
|
||||
}
|
||||
|
||||
/// Create a pair of connected sockets
|
||||
///
|
||||
/// This implementation creates a pair of SOCK_STREAM sockets.
|
||||
pub fn socketpair() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
pub fn socketpair() -> Result<(FileDescriptor, FileDescriptor)> {
|
||||
socketpair_impl()
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use crate::{
|
||||
AsRawFileDescriptor, AsRawSocketDescriptor, FileDescriptor, FromRawFileDescriptor,
|
||||
AsRawFileDescriptor, AsRawSocketDescriptor, Error, FileDescriptor, FromRawFileDescriptor,
|
||||
FromRawSocketDescriptor, IntoRawFileDescriptor, IntoRawSocketDescriptor, OwnedHandle, Pipe,
|
||||
StdioDescriptor,
|
||||
Result, StdioDescriptor,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use std::os::unix::prelude::*;
|
||||
|
||||
pub(crate) type HandleType = ();
|
||||
@ -87,32 +86,26 @@ impl FromRawFd for OwnedHandle {
|
||||
|
||||
impl OwnedHandle {
|
||||
/// Helper function to set the close-on-exec flag for a raw descriptor
|
||||
fn cloexec(&mut self) -> anyhow::Result<()> {
|
||||
fn cloexec(&mut self) -> Result<()> {
|
||||
let flags = unsafe { libc::fcntl(self.handle, libc::F_GETFD) };
|
||||
if flags == -1 {
|
||||
bail!(
|
||||
"fcntl to read flags failed: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
return Err(Error::Fcntl(std::io::Error::last_os_error()));
|
||||
}
|
||||
let result = unsafe { libc::fcntl(self.handle, libc::F_SETFD, flags | libc::FD_CLOEXEC) };
|
||||
if result == -1 {
|
||||
bail!(
|
||||
"fcntl to set CLOEXEC failed: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
Err(Error::Cloexec(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn non_atomic_dup(fd: RawFd) -> anyhow::Result<Self> {
|
||||
fn non_atomic_dup(fd: RawFd) -> Result<Self> {
|
||||
let duped = unsafe { libc::dup(fd) };
|
||||
if duped == -1 {
|
||||
bail!(
|
||||
"dup of fd {} failed: {:?}",
|
||||
fd,
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
Err(Error::Dup {
|
||||
fd: fd.into(),
|
||||
source: std::io::Error::last_os_error(),
|
||||
})
|
||||
} else {
|
||||
let mut owned = OwnedHandle {
|
||||
handle: duped,
|
||||
@ -123,15 +116,14 @@ impl OwnedHandle {
|
||||
}
|
||||
}
|
||||
|
||||
fn non_atomic_dup2(fd: RawFd, dest_fd: RawFd) -> anyhow::Result<Self> {
|
||||
fn non_atomic_dup2(fd: RawFd, dest_fd: RawFd) -> Result<Self> {
|
||||
let duped = unsafe { libc::dup2(fd, dest_fd) };
|
||||
if duped == -1 {
|
||||
bail!(
|
||||
"dup2 of fd {} and dest_fd {} failed: {:?}",
|
||||
fd,
|
||||
dest_fd,
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
Err(Error::Dup2 {
|
||||
src_fd: fd.into(),
|
||||
dest_fd: dest_fd.into(),
|
||||
source: std::io::Error::last_os_error(),
|
||||
})
|
||||
} else {
|
||||
let mut owned = OwnedHandle {
|
||||
handle: duped,
|
||||
@ -146,7 +138,7 @@ impl OwnedHandle {
|
||||
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
|
||||
fd: &F,
|
||||
handle_type: HandleType,
|
||||
) -> anyhow::Result<Self> {
|
||||
) -> Result<Self> {
|
||||
let fd = fd.as_raw_file_descriptor();
|
||||
let duped = unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) };
|
||||
if duped == -1 {
|
||||
@ -154,9 +146,12 @@ impl OwnedHandle {
|
||||
if let Some(libc::EINVAL) = err.raw_os_error() {
|
||||
// We may be running on eg: WSL or an old kernel that
|
||||
// doesn't support F_DUPFD_CLOEXEC; fall back.
|
||||
return Self::non_atomic_dup(fd);
|
||||
Self::non_atomic_dup(fd)
|
||||
} else {
|
||||
bail!("dup of fd {} failed: {:?}", fd, err)
|
||||
Err(Error::Dup {
|
||||
fd: fd.into(),
|
||||
source: err,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
Ok(OwnedHandle {
|
||||
@ -167,10 +162,7 @@ impl OwnedHandle {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn dup2_impl<F: AsRawFileDescriptor>(
|
||||
fd: &F,
|
||||
dest_fd: RawFd,
|
||||
) -> anyhow::Result<Self> {
|
||||
pub(crate) unsafe fn dup2_impl<F: AsRawFileDescriptor>(fd: &F, dest_fd: RawFd) -> Result<Self> {
|
||||
let fd = fd.as_raw_file_descriptor();
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
@ -185,20 +177,19 @@ impl OwnedHandle {
|
||||
if let Some(libc::EINVAL) = err.raw_os_error() {
|
||||
// We may be running on eg: WSL or an old kernel that
|
||||
// doesn't support O_CLOEXEC; fall back.
|
||||
return Self::non_atomic_dup2(fd, dest_fd);
|
||||
Self::non_atomic_dup2(fd, dest_fd)
|
||||
} else {
|
||||
bail!(
|
||||
"dup2 of fd {} and dest_fd {} failed: {:?}",
|
||||
fd,
|
||||
dest_fd,
|
||||
err
|
||||
)
|
||||
Err(Error::Dup2 {
|
||||
src_fd: fd.into(),
|
||||
dest_fd: dest_fd.into(),
|
||||
source: err,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
return Ok(OwnedHandle {
|
||||
Ok(OwnedHandle {
|
||||
handle: duped,
|
||||
handle_type: (),
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -209,7 +200,7 @@ impl OwnedHandle {
|
||||
}
|
||||
|
||||
impl std::io::Read for FileDescriptor {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, std::io::Error> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let size = unsafe { libc::read(self.handle.handle, buf.as_mut_ptr() as *mut _, buf.len()) };
|
||||
if size == -1 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
@ -220,7 +211,7 @@ impl std::io::Read for FileDescriptor {
|
||||
}
|
||||
|
||||
impl std::io::Write for FileDescriptor {
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
let size = unsafe { libc::write(self.handle.handle, buf.as_ptr() as *const _, buf.len()) };
|
||||
if size == -1 {
|
||||
Err(std::io::Error::last_os_error())
|
||||
@ -228,7 +219,7 @@ impl std::io::Write for FileDescriptor {
|
||||
Ok(size as usize)
|
||||
}
|
||||
}
|
||||
fn flush(&mut self) -> Result<(), std::io::Error> {
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -255,7 +246,7 @@ impl FromRawFd for FileDescriptor {
|
||||
|
||||
impl FileDescriptor {
|
||||
#[inline]
|
||||
pub(crate) fn as_stdio_impl(&self) -> anyhow::Result<std::process::Stdio> {
|
||||
pub(crate) fn as_stdio_impl(&self) -> Result<std::process::Stdio> {
|
||||
let duped = OwnedHandle::dup(self)?;
|
||||
let fd = duped.into_raw_fd();
|
||||
let stdio = unsafe { std::process::Stdio::from_raw_fd(fd) };
|
||||
@ -263,16 +254,14 @@ impl FileDescriptor {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> anyhow::Result<()> {
|
||||
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> Result<()> {
|
||||
let on = if non_blocking { 1 } else { 0 };
|
||||
let res = unsafe { libc::ioctl(self.handle.as_raw_file_descriptor(), libc::FIONBIO, &on) };
|
||||
if res != 0 {
|
||||
bail!(
|
||||
"failed to change non-blocking mode: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
Err(Error::FionBio(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempt to duplicate the underlying handle from an object that is
|
||||
@ -282,14 +271,14 @@ impl FileDescriptor {
|
||||
/// resources that may not be available, this is a potentially fallible operation.
|
||||
/// The returned handle has a separate lifetime from the source, but
|
||||
/// references the same object at the kernel level.
|
||||
pub unsafe fn dup2<F: AsRawFileDescriptor>(f: &F, dest_fd: RawFd) -> anyhow::Result<Self> {
|
||||
pub unsafe fn dup2<F: AsRawFileDescriptor>(f: &F, dest_fd: RawFd) -> Result<Self> {
|
||||
OwnedHandle::dup2_impl(f, dest_fd).map(|handle| Self { handle })
|
||||
}
|
||||
|
||||
pub(crate) fn redirect_stdio_impl<F: AsRawFileDescriptor>(
|
||||
f: &F,
|
||||
stdio: StdioDescriptor,
|
||||
) -> anyhow::Result<Self> {
|
||||
) -> Result<Self> {
|
||||
let std_descriptor = match stdio {
|
||||
StdioDescriptor::Stdin => libc::STDIN_FILENO,
|
||||
StdioDescriptor::Stdout => libc::STDOUT_FILENO,
|
||||
@ -305,14 +294,11 @@ impl FileDescriptor {
|
||||
|
||||
impl Pipe {
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn new() -> anyhow::Result<Pipe> {
|
||||
pub fn new() -> Result<Pipe> {
|
||||
let mut fds = [-1i32; 2];
|
||||
let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_CLOEXEC) };
|
||||
if res == -1 {
|
||||
bail!(
|
||||
"failed to create a pipe: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
Err(Error::Pipe(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
let read = FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
@ -331,7 +317,7 @@ impl Pipe {
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
pub fn new() -> anyhow::Result<Pipe> {
|
||||
pub fn new() -> Result<Pipe> {
|
||||
let mut fds = [-1i32; 2];
|
||||
let res = unsafe { libc::pipe(fds.as_mut_ptr()) };
|
||||
if res == -1 {
|
||||
@ -361,7 +347,7 @@ impl Pipe {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[doc(hidden)]
|
||||
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
|
||||
let mut fds = [-1i32; 2];
|
||||
let res = unsafe {
|
||||
libc::socketpair(
|
||||
@ -372,10 +358,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
)
|
||||
};
|
||||
if res == -1 {
|
||||
bail!(
|
||||
"failed to create a socketpair: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
Err(Error::Socketpair(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
let read = FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
@ -395,7 +378,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
#[doc(hidden)]
|
||||
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
|
||||
let mut fds = [-1i32; 2];
|
||||
let res = unsafe { libc::socketpair(libc::PF_LOCAL, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) };
|
||||
if res == -1 {
|
||||
@ -427,7 +410,7 @@ use std::time::Duration;
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
#[doc(hidden)]
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
|
||||
let poll_result = unsafe {
|
||||
libc::poll(
|
||||
pfd.as_mut_ptr(),
|
||||
@ -438,7 +421,7 @@ pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Resu
|
||||
)
|
||||
};
|
||||
if poll_result < 0 {
|
||||
Err(std::io::Error::last_os_error().into())
|
||||
Err(Error::Poll(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(poll_result as usize)
|
||||
}
|
||||
@ -456,12 +439,13 @@ mod macos {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn check_fd(fd: RawFd) -> anyhow::Result<()> {
|
||||
anyhow::ensure!(fd >= 0, "illegal fd value");
|
||||
anyhow::ensure!(
|
||||
(fd as usize) < FD_SETSIZE,
|
||||
"fd value is too large to use with select(2) on macos"
|
||||
);
|
||||
fn check_fd(fd: RawFd) -> Result<()> {
|
||||
if fd < 0 {
|
||||
return Err(Error::IllegalFdValue(fd.into()));
|
||||
}
|
||||
if fd >= FD_SETSIZE {
|
||||
return Err(Error::FdValueOutsideFdSetSize(fd.into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -474,7 +458,7 @@ mod macos {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&mut self, fd: RawFd) -> anyhow::Result<()> {
|
||||
pub fn add(&mut self, fd: RawFd) -> Result<()> {
|
||||
check_fd(fd)?;
|
||||
unsafe {
|
||||
FD_SET(fd, &mut self.set);
|
||||
@ -502,7 +486,7 @@ mod macos {
|
||||
set.as_mut().map(|s| s.contains(fd)).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
|
||||
let mut read_set = None;
|
||||
let mut write_set = None;
|
||||
let mut exception_set = None;
|
||||
|
@ -3,7 +3,6 @@ use crate::{
|
||||
FromRawSocketDescriptor, IntoRawFileDescriptor, IntoRawSocketDescriptor, OwnedHandle, Pipe,
|
||||
StdioDescriptor,
|
||||
};
|
||||
use anyhow::bail;
|
||||
use std::io::{self, Error as IoError};
|
||||
use std::os::windows::prelude::*;
|
||||
use std::ptr;
|
||||
@ -178,10 +177,7 @@ impl FromRawHandle for OwnedHandle {
|
||||
|
||||
impl OwnedHandle {
|
||||
#[inline]
|
||||
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(
|
||||
f: &F,
|
||||
handle_type: HandleType,
|
||||
) -> anyhow::Result<Self> {
|
||||
pub(crate) fn dup_impl<F: AsRawFileDescriptor>(f: &F, handle_type: HandleType) -> Result<Self> {
|
||||
let handle = f.as_raw_file_descriptor();
|
||||
if handle == INVALID_HANDLE_VALUE as _ || handle.is_null() {
|
||||
return Ok(OwnedHandle {
|
||||
@ -232,7 +228,7 @@ impl IntoRawHandle for OwnedHandle {
|
||||
|
||||
impl FileDescriptor {
|
||||
#[inline]
|
||||
pub(crate) fn as_stdio_impl(&self) -> anyhow::Result<std::process::Stdio> {
|
||||
pub(crate) fn as_stdio_impl(&self) -> Result<std::process::Stdio> {
|
||||
let duped = self.handle.try_clone()?;
|
||||
let handle = duped.into_raw_handle();
|
||||
let stdio = unsafe { std::process::Stdio::from_raw_handle(handle) };
|
||||
@ -240,9 +236,9 @@ impl FileDescriptor {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> anyhow::Result<()> {
|
||||
pub(crate) fn set_non_blocking_impl(&mut self, non_blocking: bool) -> Result<()> {
|
||||
if !self.handle.is_socket_handle() {
|
||||
bail!("only socket descriptors can change their non-blocking mode on windows");
|
||||
return Err(Error::OnlySocketsNonBlocking);
|
||||
}
|
||||
|
||||
let mut on = if non_blocking { 1 } else { 0 };
|
||||
@ -254,18 +250,16 @@ impl FileDescriptor {
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
bail!(
|
||||
"failed to change non-blocking mode: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
Err(Error::FionBio(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn redirect_stdio_impl<F: AsRawFileDescriptor>(
|
||||
f: &F,
|
||||
stdio: StdioDescriptor,
|
||||
) -> anyhow::Result<Self> {
|
||||
) -> Result<Self> {
|
||||
let std_handle = match stdio {
|
||||
StdioDescriptor::Stdin => STD_INPUT_HANDLE,
|
||||
StdioDescriptor::Stdout => STD_OUTPUT_HANDLE,
|
||||
@ -277,13 +271,10 @@ impl FileDescriptor {
|
||||
|
||||
let cloned_handle = OwnedHandle::dup(f)?;
|
||||
if unsafe { SetStdHandle(std_handle, cloned_handle.into_raw_handle() as *mut _) } == 0 {
|
||||
bail!(
|
||||
"failed to redirect stdio to file handle: {:?}",
|
||||
std::io::Error::last_os_error()
|
||||
);
|
||||
Err(Error::SetStdHandle(std::io::Error::last_os_error()))
|
||||
} else {
|
||||
Ok(std_original)
|
||||
}
|
||||
|
||||
Ok(std_original)
|
||||
}
|
||||
}
|
||||
|
||||
@ -415,7 +406,7 @@ impl io::Write for FileDescriptor {
|
||||
}
|
||||
|
||||
impl Pipe {
|
||||
pub fn new() -> anyhow::Result<Pipe> {
|
||||
pub fn new() -> Result<Pipe> {
|
||||
let mut sa = SECURITY_ATTRIBUTES {
|
||||
nLength: std::mem::size_of::<SECURITY_ATTRIBUTES>() as u32,
|
||||
lpSecurityDescriptor: ptr::null_mut(),
|
||||
@ -424,22 +415,23 @@ impl Pipe {
|
||||
let mut read: HANDLE = INVALID_HANDLE_VALUE as _;
|
||||
let mut write: HANDLE = INVALID_HANDLE_VALUE as _;
|
||||
if unsafe { CreatePipe(&mut read, &mut write, &mut sa, 0) } == 0 {
|
||||
bail!("CreatePipe failed: {}", IoError::last_os_error());
|
||||
Err(Error::Pipe(IoError::last_os_error()))
|
||||
} else {
|
||||
Ok(Pipe {
|
||||
read: FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: read as _,
|
||||
handle_type: HandleType::Pipe,
|
||||
},
|
||||
},
|
||||
write: FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: write as _,
|
||||
handle_type: HandleType::Pipe,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
Ok(Pipe {
|
||||
read: FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: read as _,
|
||||
handle_type: HandleType::Pipe,
|
||||
},
|
||||
},
|
||||
write: FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: write as _,
|
||||
handle_type: HandleType::Pipe,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,7 +447,7 @@ fn init_winsock() {
|
||||
});
|
||||
}
|
||||
|
||||
fn socket(af: i32, sock_type: i32, proto: i32) -> anyhow::Result<FileDescriptor> {
|
||||
fn socket(af: i32, sock_type: i32, proto: i32) -> Result<FileDescriptor> {
|
||||
let s = unsafe {
|
||||
WSASocketW(
|
||||
af,
|
||||
@ -467,18 +459,19 @@ fn socket(af: i32, sock_type: i32, proto: i32) -> anyhow::Result<FileDescriptor>
|
||||
)
|
||||
};
|
||||
if s == INVALID_SOCKET {
|
||||
bail!("socket failed: {}", IoError::last_os_error());
|
||||
Err(Error::Socket(IoError::last_os_error()))
|
||||
} else {
|
||||
Ok(FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: s as _,
|
||||
handle_type: HandleType::Socket,
|
||||
},
|
||||
})
|
||||
}
|
||||
Ok(FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
handle: s as _,
|
||||
handle_type: HandleType::Socket,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
pub fn socketpair_impl() -> Result<(FileDescriptor, FileDescriptor)> {
|
||||
init_winsock();
|
||||
|
||||
let s = socket(AF_INET, SOCK_STREAM, 0)?;
|
||||
@ -496,7 +489,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
std::mem::size_of_val(&in_addr) as _,
|
||||
) != 0
|
||||
{
|
||||
bail!("bind failed: {}", IoError::last_os_error());
|
||||
return Err(Error::Bind(IoError::last_os_error()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -509,13 +502,13 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
&mut addr_len,
|
||||
) != 0
|
||||
{
|
||||
bail!("getsockname failed: {}", IoError::last_os_error());
|
||||
return Err(Error::Getsockname(IoError::last_os_error()));
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
if listen(s.as_raw_handle() as _, 1) != 0 {
|
||||
bail!("listen failed: {}", IoError::last_os_error());
|
||||
return Err(Error::Listen(IoError::last_os_error()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,13 +521,13 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
addr_len,
|
||||
) != 0
|
||||
{
|
||||
bail!("connect failed: {}", IoError::last_os_error());
|
||||
return Err(Error::Connect(IoError::last_os_error()));
|
||||
}
|
||||
}
|
||||
|
||||
let server = unsafe { accept(s.as_raw_handle() as _, ptr::null_mut(), ptr::null_mut()) };
|
||||
if server == INVALID_SOCKET {
|
||||
bail!("socket failed: {}", IoError::last_os_error());
|
||||
return Err(Error::Accept(IoError::last_os_error()));
|
||||
}
|
||||
let server = FileDescriptor {
|
||||
handle: OwnedHandle {
|
||||
@ -547,7 +540,7 @@ pub fn socketpair_impl() -> anyhow::Result<(FileDescriptor, FileDescriptor)> {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> anyhow::Result<usize> {
|
||||
pub fn poll_impl(pfd: &mut [pollfd], duration: Option<Duration>) -> Result<usize> {
|
||||
let poll_result = unsafe {
|
||||
WSAPoll(
|
||||
pfd.as_mut_ptr(),
|
||||
|
@ -14,7 +14,7 @@ bintree = { path = "../bintree" }
|
||||
config = { path = "../config" }
|
||||
crossbeam = "0.8"
|
||||
downcast-rs = "1.0"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
lazy_static = "1.4"
|
||||
libc = "0.2"
|
||||
log = "0.4"
|
||||
|
@ -10,7 +10,7 @@ documentation = "https://docs.rs/portable-pty"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
log = "0.4"
|
||||
libc = "0.2"
|
||||
shell-words = "1.0"
|
||||
|
@ -16,7 +16,7 @@ bitflags = "1.0"
|
||||
cassowary = {version="0.3", optional=true}
|
||||
cfg-if = "1.0"
|
||||
anyhow = "1.0"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
fnv = {version="1.0", optional=true}
|
||||
lazy_static = "1.4"
|
||||
libc = "0.2"
|
||||
|
@ -69,6 +69,9 @@ pub enum InternalError {
|
||||
#[error(transparent)]
|
||||
Terminfo(#[from] terminfo::Error),
|
||||
|
||||
#[error(transparent)]
|
||||
FileDescriptor(#[from] filedescriptor::Error),
|
||||
|
||||
#[error("{}", .context)]
|
||||
Context {
|
||||
context: String,
|
||||
|
@ -4,6 +4,7 @@ use filedescriptor::{poll, pollfd, FileDescriptor, POLLIN};
|
||||
use libc::{self, winsize};
|
||||
use signal_hook::{self, SigId};
|
||||
use std::collections::VecDeque;
|
||||
use std::error::Error as _;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{stdin, stdout, Error as IoError, ErrorKind, Read, Write};
|
||||
use std::mem;
|
||||
@ -422,8 +423,12 @@ impl Terminal for UnixTerminal {
|
||||
];
|
||||
|
||||
if let Err(err) = poll(&mut pfd, wait) {
|
||||
return match err.downcast::<std::io::Error>() {
|
||||
Ok(err) => {
|
||||
return match err
|
||||
.source()
|
||||
.ok_or_else(|| anyhow::anyhow!("error has no source! {:#}", err))?
|
||||
.downcast_ref::<std::io::Error>()
|
||||
{
|
||||
Some(err) => {
|
||||
if err.kind() == ErrorKind::Interrupted {
|
||||
// SIGWINCH may have been the source of the interrupt.
|
||||
// Check for that now so that we reduce the latency of
|
||||
@ -437,7 +442,7 @@ impl Terminal for UnixTerminal {
|
||||
bail!("poll(2) error: {}", err)
|
||||
}
|
||||
}
|
||||
Err(err) => bail!("poll(2) error: {}", err),
|
||||
None => bail!("poll(2) error: {}", err),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,7 @@ async-trait = "0.1"
|
||||
async_ossl = { path = "../async_ossl" }
|
||||
codec = { path = "../codec" }
|
||||
config = { path = "../config" }
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
futures = "0.3"
|
||||
log = "0.4"
|
||||
lru = "0.6"
|
||||
|
@ -25,7 +25,7 @@ config = { path = "../config" }
|
||||
downcast-rs = "1.0"
|
||||
env-bootstrap = { path = "../env-bootstrap" }
|
||||
euclid = "0.22"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
hdrhistogram = "7.1"
|
||||
http_req = {version="0.7", default-features=false, features=["rust-tls"]}
|
||||
image = "0.23"
|
||||
|
@ -14,7 +14,7 @@ documentation = "https://docs.rs/wezterm-ssh"
|
||||
anyhow = "1.0"
|
||||
base64 = "0.13"
|
||||
dirs-next = "2.0"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
log = "0.4"
|
||||
portable-pty = { version="0.4", path = "../pty" }
|
||||
regex = "1"
|
||||
|
@ -64,15 +64,13 @@ impl portable_pty::MasterPty for SshPty {
|
||||
}
|
||||
|
||||
fn try_clone_reader(&self) -> anyhow::Result<Box<(dyn Read + Send + 'static)>> {
|
||||
self.reader
|
||||
.try_clone()
|
||||
.map(|f| -> Box<(dyn Read + Send + 'static)> { Box::new(f) })
|
||||
let reader = self.reader.try_clone()?;
|
||||
Ok(Box::new(reader))
|
||||
}
|
||||
|
||||
fn try_clone_writer(&self) -> anyhow::Result<Box<(dyn Write + Send + 'static)>> {
|
||||
self.writer
|
||||
.try_clone()
|
||||
.map(|f| -> Box<(dyn Write + Send + 'static)> { Box::new(f) })
|
||||
let writer = self.writer.try_clone()?;
|
||||
Ok(Box::new(writer))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
|
@ -14,7 +14,7 @@ anyhow = "1.0"
|
||||
codec = { path = "../codec" }
|
||||
config = { path = "../config" }
|
||||
env-bootstrap = { path = "../env-bootstrap" }
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
hostname = "0.3"
|
||||
log = "0.4"
|
||||
mux = { path = "../mux" }
|
||||
|
@ -53,7 +53,7 @@ shared_library = "0.1"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||
dirs-next = "2.0"
|
||||
filedescriptor = { version="0.7", path = "../filedescriptor" }
|
||||
filedescriptor = { version="0.8", path = "../filedescriptor" }
|
||||
x11 = {version ="2.18", features = ["xlib_xcb"]}
|
||||
xcb = {version="0.9", features=["render", "xkb", "xlib_xcb"]}
|
||||
xcb-util = { features = [ "cursor", "image", "icccm", "ewmh", "keysyms"], version = "0.3" }
|
||||
|
Loading…
Reference in New Issue
Block a user