diff --git a/crates/wasi-common/src/error.rs b/crates/wasi-common/src/error.rs index 4ce56bbc57..3da299f91b 100644 --- a/crates/wasi-common/src/error.rs +++ b/crates/wasi-common/src/error.rs @@ -101,9 +101,6 @@ pub enum Error { Wasi(#[from] WasiError), #[error("IO error: {0}")] Io(#[from] std::io::Error), - #[cfg(unix)] - #[error("Yanix error: {0}")] - Yanix(#[from] yanix::YanixError), } impl From for Error { @@ -150,16 +147,6 @@ impl Error { }; err.as_wasi_error() } - #[cfg(unix)] - Self::Yanix(err) => { - use yanix::YanixError::*; - let err: Self = match err { - Errno(errno) => (*errno).into(), - NulError(err) => err.into(), - TryFromIntError(err) => (*err).into(), - }; - err.as_wasi_error() - } } } diff --git a/crates/wasi-common/src/old/snapshot_0/error.rs b/crates/wasi-common/src/old/snapshot_0/error.rs index ae634520d3..83f137e03c 100644 --- a/crates/wasi-common/src/old/snapshot_0/error.rs +++ b/crates/wasi-common/src/old/snapshot_0/error.rs @@ -101,9 +101,6 @@ pub enum Error { Wasi(#[from] WasiError), #[error("IO error: {0}")] Io(#[from] std::io::Error), - #[cfg(unix)] - #[error("Yanix error: {0}")] - Yanix(#[from] yanix::YanixError), } impl From for Error { @@ -150,16 +147,6 @@ impl Error { }; err.as_wasi_error() } - #[cfg(unix)] - Self::Yanix(err) => { - use yanix::YanixError::*; - let err: Self = match err { - Errno(errno) => (*errno).into(), - NulError(err) => err.into(), - TryFromIntError(err) => (*err).into(), - }; - err.as_wasi_error() - } } } diff --git a/crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/hostcalls_impl.rs b/crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/hostcalls_impl.rs index 48736ac7df..e6c62860d5 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/hostcalls_impl.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/unix/bsd/hostcalls_impl.rs @@ -1,142 +1,139 @@ use crate::old::snapshot_0::hostcalls_impl::PathGet; use crate::old::snapshot_0::{Error, Result}; -use std::os::unix::prelude::AsRawFd; +use std::{io, os::unix::prelude::AsRawFd}; pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { - use yanix::{ - file::{unlinkat, AtFlag}, - Errno, YanixError, - }; - unsafe { + use yanix::file::{unlinkat, AtFlag}; + match unsafe { unlinkat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::empty(), ) - } - .map_err(|err| { - if let YanixError::Errno(mut errno) = err { - // Non-Linux implementations may return EPERM when attempting to remove a - // directory without REMOVEDIR. While that's what POSIX specifies, it's - // less useful. Adjust this to EISDIR. It doesn't matter that this is not - // atomic with the unlinkat, because if the file is removed and a directory - // is created before fstatat sees it, we're racing with that change anyway - // and unlinkat could have legitimately seen the directory if the race had - // turned out differently. - use yanix::file::{fstatat, FileType}; + } { + Err(err) => { + if let yanix::Error::Io(ref errno) = err { + let raw_errno = errno.raw_os_error().unwrap(); + // Non-Linux implementations may return EPERM when attempting to remove a + // directory without REMOVEDIR. While that's what POSIX specifies, it's + // less useful. Adjust this to EISDIR. It doesn't matter that this is not + // atomic with the unlinkat, because if the file is removed and a directory + // is created before fstatat sees it, we're racing with that change anyway + // and unlinkat could have legitimately seen the directory if the race had + // turned out differently. + use yanix::file::{fstatat, FileType}; - if errno == Errno::EPERM { - if let Ok(stat) = unsafe { - fstatat( - resolved.dirfd().as_raw_fd(), - resolved.path(), - AtFlag::SYMLINK_NOFOLLOW, - ) - } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { - errno = Errno::EISDIR; + if raw_errno == libc::EPERM { + match unsafe { + fstatat( + resolved.dirfd().as_raw_fd(), + resolved.path(), + AtFlag::SYMLINK_NOFOLLOW, + ) + } { + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { + return Err(io::Error::from_raw_os_error(libc::EISDIR).into()); + } + } + Err(err) => { + log::debug!("path_unlink_file fstatat error: {:?}", err); + } } - } else { - errno = Errno::last(); } } - errno.into() - } else { - err + + Err(err.into()) } - }) - .map_err(Into::into) + Ok(()) => Ok(()), + } } pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { - use yanix::{ - file::{fstatat, symlinkat, AtFlag}, - Errno, YanixError, - }; + use yanix::file::{fstatat, symlinkat, AtFlag}; log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink resolved = {:?}", resolved); - unsafe { symlinkat(old_path, resolved.dirfd().as_raw_fd(), resolved.path()) }.or_else(|err| { - if let YanixError::Errno(errno) = err { - match errno { - Errno::ENOTDIR => { + match unsafe { symlinkat(old_path, resolved.dirfd().as_raw_fd(), resolved.path()) } { + Err(err) => { + if let yanix::Error::Io(ref errno) = err { + if errno.raw_os_error().unwrap() == libc::ENOTDIR { // On BSD, symlinkat returns ENOTDIR when it should in fact // return a EEXIST. It seems that it gets confused with by // the trailing slash in the target path. Thus, we strip // the trailing slash and check if the path exists, and // adjust the error code appropriately. let new_path = resolved.path().trim_end_matches('/'); - if let Ok(_) = unsafe { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), new_path, AtFlag::SYMLINK_NOFOLLOW, ) } { - Err(Error::EEXIST) - } else { - Err(Error::ENOTDIR) + Ok(_) => return Err(Error::EEXIST), + Err(err) => { + log::debug!("path_symlink fstatat error: {:?}", err); + } } } - x => Err(x.into()), } - } else { Err(err.into()) } - }) + Ok(()) => Ok(()), + } } pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { - use yanix::{ - file::{fstatat, renameat, AtFlag}, - Errno, YanixError, - }; - unsafe { + use yanix::file::{fstatat, renameat, AtFlag}; + match unsafe { renameat( resolved_old.dirfd().as_raw_fd(), resolved_old.path(), resolved_new.dirfd().as_raw_fd(), resolved_new.path(), ) - } - .or_else(|err| { - // Currently, this is verified to be correct on macOS, where - // ENOENT can be returned in case when we try to rename a file - // into a name with a trailing slash. On macOS, if the latter does - // not exist, an ENOENT is thrown, whereas on Linux we observe the - // correct behaviour of throwing an ENOTDIR since the destination is - // indeed not a directory. - // - // TODO - // Verify on other BSD-based OSes. - if let YanixError::Errno(errno) = err { - match errno { - Errno::ENOENT => { + } { + Err(err) => { + // Currently, this is verified to be correct on macOS, where + // ENOENT can be returned in case when we try to rename a file + // into a name with a trailing slash. On macOS, if the latter does + // not exist, an ENOENT is thrown, whereas on Linux we observe the + // correct behaviour of throwing an ENOTDIR since the destination is + // indeed not a directory. + // + // TODO + // Verify on other BSD-based OSes. + if let yanix::Error::Io(ref errno) = err { + if errno.raw_os_error().unwrap() == libc::ENOENT { // check if the source path exists - if let Ok(_) = unsafe { + match unsafe { fstatat( resolved_old.dirfd().as_raw_fd(), resolved_old.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - // check if destination contains a trailing slash - if resolved_new.path().contains('/') { - Err(Error::ENOTDIR) - } else { - Err(Error::ENOENT) + Ok(_) => { + // check if destination contains a trailing slash + if resolved_new.path().contains('/') { + return Err(Error::ENOTDIR); + } else { + return Err(Error::ENOENT); + } + } + Err(err) => { + log::debug!("path_rename fstatat error: {:?}", err); } - } else { - Err(Error::ENOENT) } } - x => Err(x.into()), } - } else { + Err(err.into()) } - }) + Ok(()) => Ok(()), + } } pub(crate) mod fd_readdir_impl { diff --git a/crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs b/crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs index 63f92d5ce3..d10e092d06 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/unix/host_impl.rs @@ -8,93 +8,102 @@ use crate::old::snapshot_0::{ }; use std::ffi::OsStr; use std::os::unix::prelude::OsStrExt; -use yanix::{file::OFlag, Errno}; +use yanix::file::OFlag; pub(crate) use sys_impl::host_impl::*; -impl FromRawOsError for Error { - fn from_raw_os_error(code: i32) -> Self { - Self::from(Errno::from_i32(code)) +impl From for Error { + fn from(err: yanix::Error) -> Self { + use yanix::Error::*; + match err { + Io(err) => err.into(), + Nul(err) => err.into(), + IntConversion(err) => err.into(), + } } } -impl From for Error { - fn from(errno: Errno) -> Self { - match errno { - Errno::EPERM => Self::EPERM, - Errno::ENOENT => Self::ENOENT, - Errno::ESRCH => Self::ESRCH, - Errno::EINTR => Self::EINTR, - Errno::EIO => Self::EIO, - Errno::ENXIO => Self::ENXIO, - Errno::E2BIG => Self::E2BIG, - Errno::ENOEXEC => Self::ENOEXEC, - Errno::EBADF => Self::EBADF, - Errno::ECHILD => Self::ECHILD, - Errno::EAGAIN => Self::EAGAIN, - Errno::ENOMEM => Self::ENOMEM, - Errno::EACCES => Self::EACCES, - Errno::EFAULT => Self::EFAULT, - Errno::EBUSY => Self::EBUSY, - Errno::EEXIST => Self::EEXIST, - Errno::EXDEV => Self::EXDEV, - Errno::ENODEV => Self::ENODEV, - Errno::ENOTDIR => Self::ENOTDIR, - Errno::EISDIR => Self::EISDIR, - Errno::EINVAL => Self::EINVAL, - Errno::ENFILE => Self::ENFILE, - Errno::EMFILE => Self::EMFILE, - Errno::ENOTTY => Self::ENOTTY, - Errno::ETXTBSY => Self::ETXTBSY, - Errno::EFBIG => Self::EFBIG, - Errno::ENOSPC => Self::ENOSPC, - Errno::ESPIPE => Self::ESPIPE, - Errno::EROFS => Self::EROFS, - Errno::EMLINK => Self::EMLINK, - Errno::EPIPE => Self::EPIPE, - Errno::EDOM => Self::EDOM, - Errno::ERANGE => Self::ERANGE, - Errno::EDEADLK => Self::EDEADLK, - Errno::ENAMETOOLONG => Self::ENAMETOOLONG, - Errno::ENOLCK => Self::ENOLCK, - Errno::ENOSYS => Self::ENOSYS, - Errno::ENOTEMPTY => Self::ENOTEMPTY, - Errno::ELOOP => Self::ELOOP, - Errno::ENOMSG => Self::ENOMSG, - Errno::EIDRM => Self::EIDRM, - Errno::ENOLINK => Self::ENOLINK, - Errno::EPROTO => Self::EPROTO, - Errno::EMULTIHOP => Self::EMULTIHOP, - Errno::EBADMSG => Self::EBADMSG, - Errno::EOVERFLOW => Self::EOVERFLOW, - Errno::EILSEQ => Self::EILSEQ, - Errno::ENOTSOCK => Self::ENOTSOCK, - Errno::EDESTADDRREQ => Self::EDESTADDRREQ, - Errno::EMSGSIZE => Self::EMSGSIZE, - Errno::EPROTOTYPE => Self::EPROTOTYPE, - Errno::ENOPROTOOPT => Self::ENOPROTOOPT, - Errno::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, - Errno::EAFNOSUPPORT => Self::EAFNOSUPPORT, - Errno::EADDRINUSE => Self::EADDRINUSE, - Errno::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, - Errno::ENETDOWN => Self::ENETDOWN, - Errno::ENETUNREACH => Self::ENETUNREACH, - Errno::ENETRESET => Self::ENETRESET, - Errno::ECONNABORTED => Self::ECONNABORTED, - Errno::ECONNRESET => Self::ECONNRESET, - Errno::ENOBUFS => Self::ENOBUFS, - Errno::EISCONN => Self::EISCONN, - Errno::ENOTCONN => Self::ENOTCONN, - Errno::ETIMEDOUT => Self::ETIMEDOUT, - Errno::ECONNREFUSED => Self::ECONNREFUSED, - Errno::EHOSTUNREACH => Self::EHOSTUNREACH, - Errno::EALREADY => Self::EALREADY, - Errno::EINPROGRESS => Self::EINPROGRESS, - Errno::ESTALE => Self::ESTALE, - Errno::EDQUOT => Self::EDQUOT, - Errno::ECANCELED => Self::ECANCELED, - Errno::EOWNERDEAD => Self::EOWNERDEAD, - Errno::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, +impl FromRawOsError for Error { + fn from_raw_os_error(code: i32) -> Self { + match code { + libc::EPERM => Self::EPERM, + libc::ENOENT => Self::ENOENT, + libc::ESRCH => Self::ESRCH, + libc::EINTR => Self::EINTR, + libc::EIO => Self::EIO, + libc::ENXIO => Self::ENXIO, + libc::E2BIG => Self::E2BIG, + libc::ENOEXEC => Self::ENOEXEC, + libc::EBADF => Self::EBADF, + libc::ECHILD => Self::ECHILD, + libc::EAGAIN => Self::EAGAIN, + libc::ENOMEM => Self::ENOMEM, + libc::EACCES => Self::EACCES, + libc::EFAULT => Self::EFAULT, + libc::EBUSY => Self::EBUSY, + libc::EEXIST => Self::EEXIST, + libc::EXDEV => Self::EXDEV, + libc::ENODEV => Self::ENODEV, + libc::ENOTDIR => Self::ENOTDIR, + libc::EISDIR => Self::EISDIR, + libc::EINVAL => Self::EINVAL, + libc::ENFILE => Self::ENFILE, + libc::EMFILE => Self::EMFILE, + libc::ENOTTY => Self::ENOTTY, + libc::ETXTBSY => Self::ETXTBSY, + libc::EFBIG => Self::EFBIG, + libc::ENOSPC => Self::ENOSPC, + libc::ESPIPE => Self::ESPIPE, + libc::EROFS => Self::EROFS, + libc::EMLINK => Self::EMLINK, + libc::EPIPE => Self::EPIPE, + libc::EDOM => Self::EDOM, + libc::ERANGE => Self::ERANGE, + libc::EDEADLK => Self::EDEADLK, + libc::ENAMETOOLONG => Self::ENAMETOOLONG, + libc::ENOLCK => Self::ENOLCK, + libc::ENOSYS => Self::ENOSYS, + libc::ENOTEMPTY => Self::ENOTEMPTY, + libc::ELOOP => Self::ELOOP, + libc::ENOMSG => Self::ENOMSG, + libc::EIDRM => Self::EIDRM, + libc::ENOLINK => Self::ENOLINK, + libc::EPROTO => Self::EPROTO, + libc::EMULTIHOP => Self::EMULTIHOP, + libc::EBADMSG => Self::EBADMSG, + libc::EOVERFLOW => Self::EOVERFLOW, + libc::EILSEQ => Self::EILSEQ, + libc::ENOTSOCK => Self::ENOTSOCK, + libc::EDESTADDRREQ => Self::EDESTADDRREQ, + libc::EMSGSIZE => Self::EMSGSIZE, + libc::EPROTOTYPE => Self::EPROTOTYPE, + libc::ENOPROTOOPT => Self::ENOPROTOOPT, + libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, + libc::EAFNOSUPPORT => Self::EAFNOSUPPORT, + libc::EADDRINUSE => Self::EADDRINUSE, + libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, + libc::ENETDOWN => Self::ENETDOWN, + libc::ENETUNREACH => Self::ENETUNREACH, + libc::ENETRESET => Self::ENETRESET, + libc::ECONNABORTED => Self::ECONNABORTED, + libc::ECONNRESET => Self::ECONNRESET, + libc::ENOBUFS => Self::ENOBUFS, + libc::EISCONN => Self::EISCONN, + libc::ENOTCONN => Self::ENOTCONN, + libc::ETIMEDOUT => Self::ETIMEDOUT, + libc::ECONNREFUSED => Self::ECONNREFUSED, + libc::EHOSTUNREACH => Self::EHOSTUNREACH, + libc::EALREADY => Self::EALREADY, + libc::EINPROGRESS => Self::EINPROGRESS, + libc::ESTALE => Self::ESTALE, + libc::EDQUOT => Self::EDQUOT, + libc::ECANCELED => Self::ECANCELED, + libc::EOWNERDEAD => Self::EOWNERDEAD, + libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, + x => { + log::debug!("Unknown errno value: {}", x); + Self::EIO + } } } } diff --git a/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/fs.rs b/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/fs.rs index c8a3d59734..3e73a42c29 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/fs.rs @@ -88,10 +88,7 @@ pub(crate) fn path_open( oflags: wasi::__wasi_oflags_t, fs_flags: wasi::__wasi_fdflags_t, ) -> Result { - use yanix::{ - file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}, - Errno, - }; + use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}; let mut nix_all_oflags = if read && write { OFlag::RDWR @@ -127,54 +124,59 @@ pub(crate) fn path_open( } { Ok(fd) => fd, Err(e) => { - if let yanix::YanixError::Errno(errno) = e { - match errno { + if let yanix::Error::Io(ref err) = e { + match err.raw_os_error().unwrap() { // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket - Errno::ENXIO => { - if let Ok(stat) = unsafe { + libc::ENXIO => { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { - return Err(Error::ENOTSUP); - } else { - return Err(Error::ENXIO); + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { + return Err(Error::ENOTSUP); + } + } + Err(err) => { + log::debug!("path_open fstatat error: {:?}", err); } - } else { - return Err(Error::ENXIO); } } // Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY // on a symlink. - Errno::ENOTDIR + libc::ENOTDIR if !(nix_all_oflags & (OFlag::NOFOLLOW | OFlag::DIRECTORY)).is_empty() => { - if let Ok(stat) = unsafe { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { - return Err(Error::ELOOP); + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { + return Err(Error::ELOOP); + } + } + Err(err) => { + log::debug!("path_open fstatat error: {:?}", err); } } - return Err(Error::ENOTDIR); } // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on // a symlink. - Errno::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { + libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { return Err(Error::ELOOP); } - errno => return Err(errno.into()), + _ => {} } - } else { - return Err(e.into()); } + + return Err(e.into()); } }; diff --git a/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs b/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs index f6dfbe96ea..e6e270159f 100644 --- a/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs +++ b/crates/wasi-common/src/old/snapshot_0/sys/unix/hostcalls_impl/misc.rs @@ -2,6 +2,7 @@ #![allow(unused_unsafe)] use crate::old::snapshot_0::hostcalls_impl::{ClockEventData, FdEventData}; use crate::old::snapshot_0::{wasi, Error, Result}; +use std::io; use yanix::clock::{clock_getres, clock_gettime, ClockId}; fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result { @@ -54,10 +55,7 @@ pub(crate) fn poll_oneoff( events: &mut Vec, ) -> Result<()> { use std::{convert::TryInto, os::unix::prelude::AsRawFd}; - use yanix::{ - poll::{poll, PollFd, PollFlags}, - Errno, - }; + use yanix::poll::{poll, PollFd, PollFlags}; if fd_events.is_empty() && timeout.is_none() { return Ok(()); @@ -88,10 +86,11 @@ pub(crate) fn poll_oneoff( let ready = loop { match poll(&mut poll_fds, poll_timeout) { Err(_) => { - if Errno::last() == Errno::EINTR { + let last_err = io::Error::last_os_error(); + if last_err.raw_os_error().unwrap() == libc::EINTR { continue; } - return Err(Errno::last().into()); + return Err(last_err.into()); } Ok(ready) => break ready, } diff --git a/crates/wasi-common/src/sys/unix/bsd/hostcalls_impl.rs b/crates/wasi-common/src/sys/unix/bsd/hostcalls_impl.rs index b939e8257a..207b2f4712 100644 --- a/crates/wasi-common/src/sys/unix/bsd/hostcalls_impl.rs +++ b/crates/wasi-common/src/sys/unix/bsd/hostcalls_impl.rs @@ -1,142 +1,139 @@ use crate::hostcalls_impl::PathGet; use crate::{Error, Result}; -use std::os::unix::prelude::AsRawFd; +use std::{io, os::unix::prelude::AsRawFd}; pub(crate) fn path_unlink_file(resolved: PathGet) -> Result<()> { - use yanix::{ - file::{unlinkat, AtFlag}, - Errno, YanixError, - }; - unsafe { + use yanix::file::{unlinkat, AtFlag}; + match unsafe { unlinkat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::empty(), ) - } - .map_err(|err| { - if let YanixError::Errno(mut errno) = err { - // Non-Linux implementations may return EPERM when attempting to remove a - // directory without REMOVEDIR. While that's what POSIX specifies, it's - // less useful. Adjust this to EISDIR. It doesn't matter that this is not - // atomic with the unlinkat, because if the file is removed and a directory - // is created before fstatat sees it, we're racing with that change anyway - // and unlinkat could have legitimately seen the directory if the race had - // turned out differently. - use yanix::file::{fstatat, FileType}; + } { + Err(err) => { + if let yanix::Error::Io(ref errno) = err { + let raw_errno = errno.raw_os_error().unwrap(); + // Non-Linux implementations may return EPERM when attempting to remove a + // directory without REMOVEDIR. While that's what POSIX specifies, it's + // less useful. Adjust this to EISDIR. It doesn't matter that this is not + // atomic with the unlinkat, because if the file is removed and a directory + // is created before fstatat sees it, we're racing with that change anyway + // and unlinkat could have legitimately seen the directory if the race had + // turned out differently. + use yanix::file::{fstatat, FileType}; - if errno == Errno::EPERM { - if let Ok(stat) = unsafe { - fstatat( - resolved.dirfd().as_raw_fd(), - resolved.path(), - AtFlag::SYMLINK_NOFOLLOW, - ) - } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { - errno = Errno::EISDIR; + if raw_errno == libc::EPERM { + match unsafe { + fstatat( + resolved.dirfd().as_raw_fd(), + resolved.path(), + AtFlag::SYMLINK_NOFOLLOW, + ) + } { + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Directory { + return Err(io::Error::from_raw_os_error(libc::EISDIR).into()); + } + } + Err(err) => { + log::debug!("path_unlink_file fstatat error: {:?}", err); + } } - } else { - errno = Errno::last(); } } - errno.into() - } else { - err + + Err(err.into()) } - }) - .map_err(Into::into) + Ok(()) => Ok(()), + } } pub(crate) fn path_symlink(old_path: &str, resolved: PathGet) -> Result<()> { - use yanix::{ - file::{fstatat, symlinkat, AtFlag}, - Errno, YanixError, - }; + use yanix::file::{fstatat, symlinkat, AtFlag}; log::debug!("path_symlink old_path = {:?}", old_path); log::debug!("path_symlink resolved = {:?}", resolved); - unsafe { symlinkat(old_path, resolved.dirfd().as_raw_fd(), resolved.path()) }.or_else(|err| { - if let YanixError::Errno(errno) = err { - match errno { - Errno::ENOTDIR => { + match unsafe { symlinkat(old_path, resolved.dirfd().as_raw_fd(), resolved.path()) } { + Err(err) => { + if let yanix::Error::Io(ref errno) = err { + if errno.raw_os_error().unwrap() == libc::ENOTDIR { // On BSD, symlinkat returns ENOTDIR when it should in fact // return a EEXIST. It seems that it gets confused with by // the trailing slash in the target path. Thus, we strip // the trailing slash and check if the path exists, and // adjust the error code appropriately. let new_path = resolved.path().trim_end_matches('/'); - if let Ok(_) = unsafe { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), new_path, AtFlag::SYMLINK_NOFOLLOW, ) } { - Err(Error::EEXIST) - } else { - Err(Error::ENOTDIR) + Ok(_) => return Err(Error::EEXIST), + Err(err) => { + log::debug!("path_symlink fstatat error: {:?}", err); + } } } - x => Err(x.into()), } - } else { Err(err.into()) } - }) + Ok(()) => Ok(()), + } } pub(crate) fn path_rename(resolved_old: PathGet, resolved_new: PathGet) -> Result<()> { - use yanix::{ - file::{fstatat, renameat, AtFlag}, - Errno, YanixError, - }; - unsafe { + use yanix::file::{fstatat, renameat, AtFlag}; + match unsafe { renameat( resolved_old.dirfd().as_raw_fd(), resolved_old.path(), resolved_new.dirfd().as_raw_fd(), resolved_new.path(), ) - } - .or_else(|err| { - // Currently, this is verified to be correct on macOS, where - // ENOENT can be returned in case when we try to rename a file - // into a name with a trailing slash. On macOS, if the latter does - // not exist, an ENOENT is thrown, whereas on Linux we observe the - // correct behaviour of throwing an ENOTDIR since the destination is - // indeed not a directory. - // - // TODO - // Verify on other BSD-based OSes. - if let YanixError::Errno(errno) = err { - match errno { - Errno::ENOENT => { + } { + Err(err) => { + // Currently, this is verified to be correct on macOS, where + // ENOENT can be returned in case when we try to rename a file + // into a name with a trailing slash. On macOS, if the latter does + // not exist, an ENOENT is thrown, whereas on Linux we observe the + // correct behaviour of throwing an ENOTDIR since the destination is + // indeed not a directory. + // + // TODO + // Verify on other BSD-based OSes. + if let yanix::Error::Io(ref errno) = err { + if errno.raw_os_error().unwrap() == libc::ENOENT { // check if the source path exists - if let Ok(_) = unsafe { + match unsafe { fstatat( resolved_old.dirfd().as_raw_fd(), resolved_old.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - // check if destination contains a trailing slash - if resolved_new.path().contains('/') { - Err(Error::ENOTDIR) - } else { - Err(Error::ENOENT) + Ok(_) => { + // check if destination contains a trailing slash + if resolved_new.path().contains('/') { + return Err(Error::ENOTDIR); + } else { + return Err(Error::ENOENT); + } + } + Err(err) => { + log::debug!("path_rename fstatat error: {:?}", err); } - } else { - Err(Error::ENOENT) } } - x => Err(x.into()), } - } else { + Err(err.into()) } - }) + Ok(()) => Ok(()), + } } pub(crate) mod fd_readdir_impl { diff --git a/crates/wasi-common/src/sys/unix/host_impl.rs b/crates/wasi-common/src/sys/unix/host_impl.rs index f06727fc5f..c88bd2198a 100644 --- a/crates/wasi-common/src/sys/unix/host_impl.rs +++ b/crates/wasi-common/src/sys/unix/host_impl.rs @@ -6,93 +6,102 @@ use crate::host::FileType; use crate::{error::FromRawOsError, helpers, sys::unix::sys_impl, wasi, Error, Result}; use std::ffi::OsStr; use std::os::unix::prelude::OsStrExt; -use yanix::{file::OFlag, Errno}; +use yanix::file::OFlag; pub(crate) use sys_impl::host_impl::*; -impl FromRawOsError for Error { - fn from_raw_os_error(code: i32) -> Self { - Self::from(Errno::from_i32(code)) +impl From for Error { + fn from(err: yanix::Error) -> Self { + use yanix::Error::*; + match err { + Io(err) => err.into(), + Nul(err) => err.into(), + IntConversion(err) => err.into(), + } } } -impl From for Error { - fn from(errno: Errno) -> Self { - match errno { - Errno::EPERM => Self::EPERM, - Errno::ENOENT => Self::ENOENT, - Errno::ESRCH => Self::ESRCH, - Errno::EINTR => Self::EINTR, - Errno::EIO => Self::EIO, - Errno::ENXIO => Self::ENXIO, - Errno::E2BIG => Self::E2BIG, - Errno::ENOEXEC => Self::ENOEXEC, - Errno::EBADF => Self::EBADF, - Errno::ECHILD => Self::ECHILD, - Errno::EAGAIN => Self::EAGAIN, - Errno::ENOMEM => Self::ENOMEM, - Errno::EACCES => Self::EACCES, - Errno::EFAULT => Self::EFAULT, - Errno::EBUSY => Self::EBUSY, - Errno::EEXIST => Self::EEXIST, - Errno::EXDEV => Self::EXDEV, - Errno::ENODEV => Self::ENODEV, - Errno::ENOTDIR => Self::ENOTDIR, - Errno::EISDIR => Self::EISDIR, - Errno::EINVAL => Self::EINVAL, - Errno::ENFILE => Self::ENFILE, - Errno::EMFILE => Self::EMFILE, - Errno::ENOTTY => Self::ENOTTY, - Errno::ETXTBSY => Self::ETXTBSY, - Errno::EFBIG => Self::EFBIG, - Errno::ENOSPC => Self::ENOSPC, - Errno::ESPIPE => Self::ESPIPE, - Errno::EROFS => Self::EROFS, - Errno::EMLINK => Self::EMLINK, - Errno::EPIPE => Self::EPIPE, - Errno::EDOM => Self::EDOM, - Errno::ERANGE => Self::ERANGE, - Errno::EDEADLK => Self::EDEADLK, - Errno::ENAMETOOLONG => Self::ENAMETOOLONG, - Errno::ENOLCK => Self::ENOLCK, - Errno::ENOSYS => Self::ENOSYS, - Errno::ENOTEMPTY => Self::ENOTEMPTY, - Errno::ELOOP => Self::ELOOP, - Errno::ENOMSG => Self::ENOMSG, - Errno::EIDRM => Self::EIDRM, - Errno::ENOLINK => Self::ENOLINK, - Errno::EPROTO => Self::EPROTO, - Errno::EMULTIHOP => Self::EMULTIHOP, - Errno::EBADMSG => Self::EBADMSG, - Errno::EOVERFLOW => Self::EOVERFLOW, - Errno::EILSEQ => Self::EILSEQ, - Errno::ENOTSOCK => Self::ENOTSOCK, - Errno::EDESTADDRREQ => Self::EDESTADDRREQ, - Errno::EMSGSIZE => Self::EMSGSIZE, - Errno::EPROTOTYPE => Self::EPROTOTYPE, - Errno::ENOPROTOOPT => Self::ENOPROTOOPT, - Errno::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, - Errno::EAFNOSUPPORT => Self::EAFNOSUPPORT, - Errno::EADDRINUSE => Self::EADDRINUSE, - Errno::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, - Errno::ENETDOWN => Self::ENETDOWN, - Errno::ENETUNREACH => Self::ENETUNREACH, - Errno::ENETRESET => Self::ENETRESET, - Errno::ECONNABORTED => Self::ECONNABORTED, - Errno::ECONNRESET => Self::ECONNRESET, - Errno::ENOBUFS => Self::ENOBUFS, - Errno::EISCONN => Self::EISCONN, - Errno::ENOTCONN => Self::ENOTCONN, - Errno::ETIMEDOUT => Self::ETIMEDOUT, - Errno::ECONNREFUSED => Self::ECONNREFUSED, - Errno::EHOSTUNREACH => Self::EHOSTUNREACH, - Errno::EALREADY => Self::EALREADY, - Errno::EINPROGRESS => Self::EINPROGRESS, - Errno::ESTALE => Self::ESTALE, - Errno::EDQUOT => Self::EDQUOT, - Errno::ECANCELED => Self::ECANCELED, - Errno::EOWNERDEAD => Self::EOWNERDEAD, - Errno::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, +impl FromRawOsError for Error { + fn from_raw_os_error(code: i32) -> Self { + match code { + libc::EPERM => Self::EPERM, + libc::ENOENT => Self::ENOENT, + libc::ESRCH => Self::ESRCH, + libc::EINTR => Self::EINTR, + libc::EIO => Self::EIO, + libc::ENXIO => Self::ENXIO, + libc::E2BIG => Self::E2BIG, + libc::ENOEXEC => Self::ENOEXEC, + libc::EBADF => Self::EBADF, + libc::ECHILD => Self::ECHILD, + libc::EAGAIN => Self::EAGAIN, + libc::ENOMEM => Self::ENOMEM, + libc::EACCES => Self::EACCES, + libc::EFAULT => Self::EFAULT, + libc::EBUSY => Self::EBUSY, + libc::EEXIST => Self::EEXIST, + libc::EXDEV => Self::EXDEV, + libc::ENODEV => Self::ENODEV, + libc::ENOTDIR => Self::ENOTDIR, + libc::EISDIR => Self::EISDIR, + libc::EINVAL => Self::EINVAL, + libc::ENFILE => Self::ENFILE, + libc::EMFILE => Self::EMFILE, + libc::ENOTTY => Self::ENOTTY, + libc::ETXTBSY => Self::ETXTBSY, + libc::EFBIG => Self::EFBIG, + libc::ENOSPC => Self::ENOSPC, + libc::ESPIPE => Self::ESPIPE, + libc::EROFS => Self::EROFS, + libc::EMLINK => Self::EMLINK, + libc::EPIPE => Self::EPIPE, + libc::EDOM => Self::EDOM, + libc::ERANGE => Self::ERANGE, + libc::EDEADLK => Self::EDEADLK, + libc::ENAMETOOLONG => Self::ENAMETOOLONG, + libc::ENOLCK => Self::ENOLCK, + libc::ENOSYS => Self::ENOSYS, + libc::ENOTEMPTY => Self::ENOTEMPTY, + libc::ELOOP => Self::ELOOP, + libc::ENOMSG => Self::ENOMSG, + libc::EIDRM => Self::EIDRM, + libc::ENOLINK => Self::ENOLINK, + libc::EPROTO => Self::EPROTO, + libc::EMULTIHOP => Self::EMULTIHOP, + libc::EBADMSG => Self::EBADMSG, + libc::EOVERFLOW => Self::EOVERFLOW, + libc::EILSEQ => Self::EILSEQ, + libc::ENOTSOCK => Self::ENOTSOCK, + libc::EDESTADDRREQ => Self::EDESTADDRREQ, + libc::EMSGSIZE => Self::EMSGSIZE, + libc::EPROTOTYPE => Self::EPROTOTYPE, + libc::ENOPROTOOPT => Self::ENOPROTOOPT, + libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, + libc::EAFNOSUPPORT => Self::EAFNOSUPPORT, + libc::EADDRINUSE => Self::EADDRINUSE, + libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, + libc::ENETDOWN => Self::ENETDOWN, + libc::ENETUNREACH => Self::ENETUNREACH, + libc::ENETRESET => Self::ENETRESET, + libc::ECONNABORTED => Self::ECONNABORTED, + libc::ECONNRESET => Self::ECONNRESET, + libc::ENOBUFS => Self::ENOBUFS, + libc::EISCONN => Self::EISCONN, + libc::ENOTCONN => Self::ENOTCONN, + libc::ETIMEDOUT => Self::ETIMEDOUT, + libc::ECONNREFUSED => Self::ECONNREFUSED, + libc::EHOSTUNREACH => Self::EHOSTUNREACH, + libc::EALREADY => Self::EALREADY, + libc::EINPROGRESS => Self::EINPROGRESS, + libc::ESTALE => Self::ESTALE, + libc::EDQUOT => Self::EDQUOT, + libc::ECANCELED => Self::ECANCELED, + libc::EOWNERDEAD => Self::EOWNERDEAD, + libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, + x => { + log::debug!("Unknown errno value: {}", x); + Self::EIO + } } } } diff --git a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs index a4f1fe9dd0..255d82ec9a 100644 --- a/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs +++ b/crates/wasi-common/src/sys/unix/hostcalls_impl/fs.rs @@ -93,10 +93,7 @@ pub(crate) fn path_open( oflags: wasi::__wasi_oflags_t, fs_flags: wasi::__wasi_fdflags_t, ) -> Result { - use yanix::{ - file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}, - Errno, - }; + use yanix::file::{fstatat, openat, AtFlag, FileType, Mode, OFlag}; let mut nix_all_oflags = if read && write { OFlag::RDWR @@ -132,54 +129,59 @@ pub(crate) fn path_open( } { Ok(fd) => fd, Err(e) => { - if let yanix::YanixError::Errno(errno) = e { - match errno { + if let yanix::Error::Io(ref err) = e { + match err.raw_os_error().unwrap() { // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket - Errno::ENXIO => { - if let Ok(stat) = unsafe { + libc::ENXIO => { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { - return Err(Error::ENOTSUP); - } else { - return Err(Error::ENXIO); + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Socket { + return Err(Error::ENOTSUP); + } + } + Err(err) => { + log::debug!("path_open fstatat error: {:?}", err); } - } else { - return Err(Error::ENXIO); } } // Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY // on a symlink. - Errno::ENOTDIR + libc::ENOTDIR if !(nix_all_oflags & (OFlag::NOFOLLOW | OFlag::DIRECTORY)).is_empty() => { - if let Ok(stat) = unsafe { + match unsafe { fstatat( resolved.dirfd().as_raw_fd(), resolved.path(), AtFlag::SYMLINK_NOFOLLOW, ) } { - if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { - return Err(Error::ELOOP); + Ok(stat) => { + if FileType::from_stat_st_mode(stat.st_mode) == FileType::Symlink { + return Err(Error::ELOOP); + } + } + Err(err) => { + log::debug!("path_open fstatat error: {:?}", err); } } - return Err(Error::ENOTDIR); } // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on // a symlink. - Errno::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { + libc::EMLINK if !(nix_all_oflags & OFlag::NOFOLLOW).is_empty() => { return Err(Error::ELOOP); } - errno => return Err(errno.into()), + _ => {} } - } else { - return Err(e.into()); } + + return Err(e.into()); } }; diff --git a/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs b/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs index 3e6748fbc5..678f335cad 100644 --- a/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs +++ b/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs @@ -2,6 +2,7 @@ #![allow(unused_unsafe)] use crate::hostcalls_impl::{ClockEventData, FdEventData}; use crate::{wasi, Error, Result}; +use std::io; use yanix::clock::{clock_getres, clock_gettime, ClockId}; fn wasi_clock_id_to_unix(clock_id: wasi::__wasi_clockid_t) -> Result { @@ -54,10 +55,7 @@ pub(crate) fn poll_oneoff( events: &mut Vec, ) -> Result<()> { use std::{convert::TryInto, os::unix::prelude::AsRawFd}; - use yanix::{ - poll::{poll, PollFd, PollFlags}, - Errno, - }; + use yanix::poll::{poll, PollFd, PollFlags}; if fd_events.is_empty() && timeout.is_none() { return Ok(()); @@ -88,10 +86,11 @@ pub(crate) fn poll_oneoff( let ready = loop { match poll(&mut poll_fds, poll_timeout) { Err(_) => { - if Errno::last() == Errno::EINTR { + let last_err = io::Error::last_os_error(); + if last_err.raw_os_error().unwrap() == libc::EINTR { continue; } - return Err(Errno::last().into()); + return Err(last_err.into()); } Ok(ready) => break ready, } diff --git a/crates/wasi-common/yanix/src/clock.rs b/crates/wasi-common/yanix/src/clock.rs index 1f70d18893..4d1e105b4e 100644 --- a/crates/wasi-common/yanix/src/clock.rs +++ b/crates/wasi-common/yanix/src/clock.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use std::mem::MaybeUninit; #[derive(Debug, Copy, Clone)] @@ -22,7 +22,7 @@ impl ClockId { pub fn clock_getres(clock_id: ClockId) -> Result { let mut timespec = MaybeUninit::::uninit(); - Errno::from_success_code(unsafe { + Error::from_success_code(unsafe { libc::clock_getres(clock_id.as_raw(), timespec.as_mut_ptr()) })?; Ok(unsafe { timespec.assume_init() }) @@ -30,7 +30,7 @@ pub fn clock_getres(clock_id: ClockId) -> Result { pub fn clock_gettime(clock_id: ClockId) -> Result { let mut timespec = MaybeUninit::::uninit(); - Errno::from_success_code(unsafe { + Error::from_success_code(unsafe { libc::clock_gettime(clock_id.as_raw(), timespec.as_mut_ptr()) })?; Ok(unsafe { timespec.assume_init() }) diff --git a/crates/wasi-common/yanix/src/dir.rs b/crates/wasi-common/yanix/src/dir.rs index fc13afc029..55ef823a81 100644 --- a/crates/wasi-common/yanix/src/dir.rs +++ b/crates/wasi-common/yanix/src/dir.rs @@ -1,10 +1,10 @@ use crate::{ file::FileType, sys::dir::{iter_impl, EntryImpl}, - Errno, Result, + Result, }; use std::os::unix::io::{AsRawFd, IntoRawFd, RawFd}; -use std::{ffi::CStr, ops::Deref, ptr}; +use std::{ffi::CStr, io, ops::Deref, ptr}; pub use crate::sys::EntryExt; @@ -25,7 +25,7 @@ impl Dir { if let Some(d) = ptr::NonNull::new(d) { Ok(Self(d)) } else { - let e = Errno::last(); + let e = io::Error::last_os_error(); libc::close(fd); Err(e.into()) } diff --git a/crates/wasi-common/yanix/src/errno.rs b/crates/wasi-common/yanix/src/errno.rs deleted file mode 100644 index 8f8be64dc8..0000000000 --- a/crates/wasi-common/yanix/src/errno.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! Errno-specific for different Unix platforms -use crate::Result; -use std::{fmt, io}; -use thiserror::Error; - -#[derive(Debug, Copy, Clone, Error, PartialEq, Eq, Hash)] -#[repr(i32)] -pub enum Errno { - EPERM = libc::EPERM, - ENOENT = libc::ENOENT, - ESRCH = libc::ESRCH, - EINTR = libc::EINTR, - EIO = libc::EIO, - ENXIO = libc::ENXIO, - E2BIG = libc::E2BIG, - ENOEXEC = libc::ENOEXEC, - EBADF = libc::EBADF, - ECHILD = libc::ECHILD, - EAGAIN = libc::EAGAIN, - ENOMEM = libc::ENOMEM, - EACCES = libc::EACCES, - EFAULT = libc::EFAULT, - EBUSY = libc::EBUSY, - EEXIST = libc::EEXIST, - EXDEV = libc::EXDEV, - ENODEV = libc::ENODEV, - ENOTDIR = libc::ENOTDIR, - EISDIR = libc::EISDIR, - EINVAL = libc::EINVAL, - ENFILE = libc::ENFILE, - EMFILE = libc::EMFILE, - ENOTTY = libc::ENOTTY, - ETXTBSY = libc::ETXTBSY, - EFBIG = libc::EFBIG, - ENOSPC = libc::ENOSPC, - ESPIPE = libc::ESPIPE, - EROFS = libc::EROFS, - EMLINK = libc::EMLINK, - EPIPE = libc::EPIPE, - EDOM = libc::EDOM, - ERANGE = libc::ERANGE, - EDEADLK = libc::EDEADLK, - ENAMETOOLONG = libc::ENAMETOOLONG, - ENOLCK = libc::ENOLCK, - ENOSYS = libc::ENOSYS, - ENOTEMPTY = libc::ENOTEMPTY, - ELOOP = libc::ELOOP, - ENOMSG = libc::ENOMSG, - EIDRM = libc::EIDRM, - ENOLINK = libc::ENOLINK, - EPROTO = libc::EPROTO, - EMULTIHOP = libc::EMULTIHOP, - EBADMSG = libc::EBADMSG, - EOVERFLOW = libc::EOVERFLOW, - EILSEQ = libc::EILSEQ, - ENOTSOCK = libc::ENOTSOCK, - EDESTADDRREQ = libc::EDESTADDRREQ, - EMSGSIZE = libc::EMSGSIZE, - EPROTOTYPE = libc::EPROTOTYPE, - ENOPROTOOPT = libc::ENOPROTOOPT, - EPROTONOSUPPORT = libc::EPROTONOSUPPORT, - EAFNOSUPPORT = libc::EAFNOSUPPORT, - EADDRINUSE = libc::EADDRINUSE, - EADDRNOTAVAIL = libc::EADDRNOTAVAIL, - ENETDOWN = libc::ENETDOWN, - ENETUNREACH = libc::ENETUNREACH, - ENETRESET = libc::ENETRESET, - ECONNABORTED = libc::ECONNABORTED, - ECONNRESET = libc::ECONNRESET, - ENOBUFS = libc::ENOBUFS, - EISCONN = libc::EISCONN, - ENOTCONN = libc::ENOTCONN, - ETIMEDOUT = libc::ETIMEDOUT, - ECONNREFUSED = libc::ECONNREFUSED, - EHOSTUNREACH = libc::EHOSTUNREACH, - EALREADY = libc::EALREADY, - EINPROGRESS = libc::EINPROGRESS, - ESTALE = libc::ESTALE, - EDQUOT = libc::EDQUOT, - ECANCELED = libc::ECANCELED, - EOWNERDEAD = libc::EOWNERDEAD, - ENOTRECOVERABLE = libc::ENOTRECOVERABLE, -} - -impl Errno { - pub fn from_i32(err: i32) -> Self { - match err { - libc::EPERM => Self::EPERM, - libc::ENOENT => Self::ENOENT, - libc::ESRCH => Self::ESRCH, - libc::EINTR => Self::EINTR, - libc::EIO => Self::EIO, - libc::ENXIO => Self::ENXIO, - libc::E2BIG => Self::E2BIG, - libc::ENOEXEC => Self::ENOEXEC, - libc::EBADF => Self::EBADF, - libc::ECHILD => Self::ECHILD, - libc::EAGAIN => Self::EAGAIN, - libc::ENOMEM => Self::ENOMEM, - libc::EACCES => Self::EACCES, - libc::EFAULT => Self::EFAULT, - libc::EBUSY => Self::EBUSY, - libc::EEXIST => Self::EEXIST, - libc::EXDEV => Self::EXDEV, - libc::ENODEV => Self::ENODEV, - libc::ENOTDIR => Self::ENOTDIR, - libc::EISDIR => Self::EISDIR, - libc::EINVAL => Self::EINVAL, - libc::ENFILE => Self::ENFILE, - libc::EMFILE => Self::EMFILE, - libc::ENOTTY => Self::ENOTTY, - libc::ETXTBSY => Self::ETXTBSY, - libc::EFBIG => Self::EFBIG, - libc::ENOSPC => Self::ENOSPC, - libc::ESPIPE => Self::ESPIPE, - libc::EROFS => Self::EROFS, - libc::EMLINK => Self::EMLINK, - libc::EPIPE => Self::EPIPE, - libc::EDOM => Self::EDOM, - libc::ERANGE => Self::ERANGE, - libc::EDEADLK => Self::EDEADLK, - libc::ENAMETOOLONG => Self::ENAMETOOLONG, - libc::ENOLCK => Self::ENOLCK, - libc::ENOSYS => Self::ENOSYS, - libc::ENOTEMPTY => Self::ENOTEMPTY, - libc::ELOOP => Self::ELOOP, - libc::ENOMSG => Self::ENOMSG, - libc::EIDRM => Self::EIDRM, - libc::ENOLINK => Self::ENOLINK, - libc::EPROTO => Self::EPROTO, - libc::EMULTIHOP => Self::EMULTIHOP, - libc::EBADMSG => Self::EBADMSG, - libc::EOVERFLOW => Self::EOVERFLOW, - libc::EILSEQ => Self::EILSEQ, - libc::ENOTSOCK => Self::ENOTSOCK, - libc::EDESTADDRREQ => Self::EDESTADDRREQ, - libc::EMSGSIZE => Self::EMSGSIZE, - libc::EPROTOTYPE => Self::EPROTOTYPE, - libc::ENOPROTOOPT => Self::ENOPROTOOPT, - libc::EPROTONOSUPPORT => Self::EPROTONOSUPPORT, - libc::EAFNOSUPPORT => Self::EAFNOSUPPORT, - libc::EADDRINUSE => Self::EADDRINUSE, - libc::EADDRNOTAVAIL => Self::EADDRNOTAVAIL, - libc::ENETDOWN => Self::ENETDOWN, - libc::ENETUNREACH => Self::ENETUNREACH, - libc::ENETRESET => Self::ENETRESET, - libc::ECONNABORTED => Self::ECONNABORTED, - libc::ECONNRESET => Self::ECONNRESET, - libc::ENOBUFS => Self::ENOBUFS, - libc::EISCONN => Self::EISCONN, - libc::ENOTCONN => Self::ENOTCONN, - libc::ETIMEDOUT => Self::ETIMEDOUT, - libc::ECONNREFUSED => Self::ECONNREFUSED, - libc::EHOSTUNREACH => Self::EHOSTUNREACH, - libc::EALREADY => Self::EALREADY, - libc::EINPROGRESS => Self::EINPROGRESS, - libc::ESTALE => Self::ESTALE, - libc::EDQUOT => Self::EDQUOT, - libc::ECANCELED => Self::ECANCELED, - libc::EOWNERDEAD => Self::EOWNERDEAD, - libc::ENOTRECOVERABLE => Self::ENOTRECOVERABLE, - other => { - log::warn!("Unknown errno: {}", other); - Self::ENOSYS - } - } - } - - pub fn last() -> Self { - let errno = io::Error::last_os_error() - .raw_os_error() - .unwrap_or(libc::ENOSYS); - Self::from_i32(errno) - } - - pub fn from_success_code(t: T) -> Result<()> { - if t.is_zero() { - Ok(()) - } else { - Err(Self::last().into()) - } - } - - pub fn from_result(t: T) -> Result { - if t.is_minus_one() { - Err(Self::last().into()) - } else { - Ok(t) - } - } -} - -impl fmt::Display for Errno { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Errno code: {}", self) - } -} - -#[doc(hidden)] -pub trait IsZero { - fn is_zero(&self) -> bool; -} - -macro_rules! impl_is_zero { - ($($t:ident)*) => ($(impl IsZero for $t { - fn is_zero(&self) -> bool { - *self == 0 - } - })*) -} - -impl_is_zero! { i32 i64 isize } - -#[doc(hidden)] -pub trait IsMinusOne { - fn is_minus_one(&self) -> bool; -} - -macro_rules! impl_is_minus_one { - ($($t:ident)*) => ($(impl IsMinusOne for $t { - fn is_minus_one(&self) -> bool { - *self == -1 - } - })*) -} - -impl_is_minus_one! { i32 i64 isize } diff --git a/crates/wasi-common/yanix/src/error.rs b/crates/wasi-common/yanix/src/error.rs new file mode 100644 index 0000000000..f59c046aee --- /dev/null +++ b/crates/wasi-common/yanix/src/error.rs @@ -0,0 +1,61 @@ +//! Error type +use crate::Result; +use std::{ffi, io, num}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("I/O error {0}")] + Io(#[from] io::Error), + #[error("a nul byte was not found in the expected position")] + Nul(#[from] ffi::NulError), + #[error("integral type conversion failed")] + IntConversion(#[from] num::TryFromIntError), +} + +impl Error { + pub fn from_success_code(t: T) -> Result<()> { + if t.is_zero() { + Ok(()) + } else { + Err(Self::from(io::Error::last_os_error())) + } + } + + pub fn from_result(t: T) -> Result { + if t.is_minus_one() { + Err(Self::from(io::Error::last_os_error())) + } else { + Ok(t) + } + } +} + +#[doc(hidden)] +pub trait IsZero { + fn is_zero(&self) -> bool; +} + +macro_rules! impl_is_zero { + ($($t:ident)*) => ($(impl IsZero for $t { + fn is_zero(&self) -> bool { + *self == 0 + } + })*) +} + +impl_is_zero! { i32 i64 isize } + +#[doc(hidden)] +pub trait IsMinusOne { + fn is_minus_one(&self) -> bool; +} + +macro_rules! impl_is_minus_one { + ($($t:ident)*) => ($(impl IsMinusOne for $t { + fn is_minus_one(&self) -> bool { + *self == -1 + } + })*) +} + +impl_is_minus_one! { i32 i64 isize } diff --git a/crates/wasi-common/yanix/src/fcntl.rs b/crates/wasi-common/yanix/src/fcntl.rs index 87d9827af3..3b95cbffe9 100644 --- a/crates/wasi-common/yanix/src/fcntl.rs +++ b/crates/wasi-common/yanix/src/fcntl.rs @@ -1,6 +1,6 @@ use crate::{ file::{FdFlag, OFlag}, - Errno, Result, + Error, Result, }; use std::os::unix::prelude::*; @@ -9,7 +9,7 @@ pub unsafe fn dup_fd(fd: RawFd, close_on_exec: bool) -> Result { // the minimum duplicated RawFd number. In our case, I don't // think we have to worry about this that much, so passing in // the RawFd descriptor we want duplicated - Errno::from_result(if close_on_exec { + Error::from_result(if close_on_exec { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, fd) } else { libc::fcntl(fd, libc::F_DUPFD, fd) @@ -17,17 +17,17 @@ pub unsafe fn dup_fd(fd: RawFd, close_on_exec: bool) -> Result { } pub unsafe fn get_fd_flags(fd: RawFd) -> Result { - Errno::from_result(libc::fcntl(fd, libc::F_GETFD)).map(FdFlag::from_bits_truncate) + Error::from_result(libc::fcntl(fd, libc::F_GETFD)).map(FdFlag::from_bits_truncate) } pub unsafe fn set_fd_flags(fd: RawFd, flags: FdFlag) -> Result<()> { - Errno::from_success_code(libc::fcntl(fd, libc::F_SETFD, flags.bits())) + Error::from_success_code(libc::fcntl(fd, libc::F_SETFD, flags.bits())) } pub unsafe fn get_status_flags(fd: RawFd) -> Result { - Errno::from_result(libc::fcntl(fd, libc::F_GETFL)).map(OFlag::from_bits_truncate) + Error::from_result(libc::fcntl(fd, libc::F_GETFL)).map(OFlag::from_bits_truncate) } pub unsafe fn set_status_flags(fd: RawFd, flags: OFlag) -> Result<()> { - Errno::from_success_code(libc::fcntl(fd, libc::F_SETFL, flags.bits())) + Error::from_success_code(libc::fcntl(fd, libc::F_SETFL, flags.bits())) } diff --git a/crates/wasi-common/yanix/src/file.rs b/crates/wasi-common/yanix/src/file.rs index 1124dcd95e..397740cea4 100644 --- a/crates/wasi-common/yanix/src/file.rs +++ b/crates/wasi-common/yanix/src/file.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use bitflags::bitflags; use cfg_if::cfg_if; use std::{ @@ -137,7 +137,7 @@ pub unsafe fn openat>( mode: Mode, ) -> Result { let path = CString::new(path.as_ref().as_bytes())?; - Errno::from_result(libc::openat( + Error::from_result(libc::openat( dirfd, path.as_ptr(), oflag.bits(), @@ -148,7 +148,7 @@ pub unsafe fn openat>( pub unsafe fn readlinkat>(dirfd: RawFd, path: P) -> Result { let path = CString::new(path.as_ref().as_bytes())?; let buffer = &mut [0u8; libc::PATH_MAX as usize + 1]; - Errno::from_result(libc::readlinkat( + Error::from_result(libc::readlinkat( dirfd, path.as_ptr(), buffer.as_mut_ptr() as *mut _, @@ -162,7 +162,7 @@ pub unsafe fn readlinkat>(dirfd: RawFd, path: P) -> Result>(dirfd: RawFd, path: P, mode: Mode) -> Result<()> { let path = CString::new(path.as_ref().as_bytes())?; - Errno::from_success_code(libc::mkdirat(dirfd, path.as_ptr(), mode.bits())) + Error::from_success_code(libc::mkdirat(dirfd, path.as_ptr(), mode.bits())) } pub unsafe fn linkat>( @@ -174,7 +174,7 @@ pub unsafe fn linkat>( ) -> Result<()> { let old_path = CString::new(old_path.as_ref().as_bytes())?; let new_path = CString::new(new_path.as_ref().as_bytes())?; - Errno::from_success_code(libc::linkat( + Error::from_success_code(libc::linkat( old_dirfd, old_path.as_ptr(), new_dirfd, @@ -185,7 +185,7 @@ pub unsafe fn linkat>( pub unsafe fn unlinkat>(dirfd: RawFd, path: P, flags: AtFlag) -> Result<()> { let path = CString::new(path.as_ref().as_bytes())?; - Errno::from_success_code(libc::unlinkat(dirfd, path.as_ptr(), flags.bits())) + Error::from_success_code(libc::unlinkat(dirfd, path.as_ptr(), flags.bits())) } pub unsafe fn renameat>( @@ -196,7 +196,7 @@ pub unsafe fn renameat>( ) -> Result<()> { let old_path = CString::new(old_path.as_ref().as_bytes())?; let new_path = CString::new(new_path.as_ref().as_bytes())?; - Errno::from_success_code(libc::renameat( + Error::from_success_code(libc::renameat( old_dirfd, old_path.as_ptr(), new_dirfd, @@ -207,7 +207,7 @@ pub unsafe fn renameat>( pub unsafe fn symlinkat>(old_path: P, new_dirfd: RawFd, new_path: P) -> Result<()> { let old_path = CString::new(old_path.as_ref().as_bytes())?; let new_path = CString::new(new_path.as_ref().as_bytes())?; - Errno::from_success_code(libc::symlinkat( + Error::from_success_code(libc::symlinkat( old_path.as_ptr(), new_dirfd, new_path.as_ptr(), @@ -218,7 +218,7 @@ pub unsafe fn fstatat>(dirfd: RawFd, path: P, flags: AtFlag) -> use std::mem::MaybeUninit; let path = CString::new(path.as_ref().as_bytes())?; let mut filestat = MaybeUninit::::uninit(); - Errno::from_result(libc::fstatat( + Error::from_result(libc::fstatat( dirfd, path.as_ptr(), filestat.as_mut_ptr(), @@ -230,20 +230,20 @@ pub unsafe fn fstatat>(dirfd: RawFd, path: P, flags: AtFlag) -> pub unsafe fn fstat(fd: RawFd) -> Result { use std::mem::MaybeUninit; let mut filestat = MaybeUninit::::uninit(); - Errno::from_result(libc::fstat(fd, filestat.as_mut_ptr()))?; + Error::from_result(libc::fstat(fd, filestat.as_mut_ptr()))?; Ok(filestat.assume_init()) } /// `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`. pub unsafe fn fionread(fd: RawFd) -> Result { let mut nread: libc::c_int = 0; - Errno::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?; + Error::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?; Ok(nread.try_into()?) } /// This function is unsafe because it operates on a raw file descriptor. /// It's provided, because std::io::Seek requires a mutable borrow. pub unsafe fn tell(fd: RawFd) -> Result { - let offset: i64 = Errno::from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?; + let offset: i64 = Error::from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?; Ok(offset.try_into()?) } diff --git a/crates/wasi-common/yanix/src/lib.rs b/crates/wasi-common/yanix/src/lib.rs index e97e4e0b0f..7f9361a4e9 100644 --- a/crates/wasi-common/yanix/src/lib.rs +++ b/crates/wasi-common/yanix/src/lib.rs @@ -16,25 +16,12 @@ pub mod file; pub mod poll; pub mod socket; -mod errno; +mod error; mod sys; pub mod fadvise { pub use super::sys::fadvise::*; } -pub use errno::Errno; -use std::{ffi, num}; -use thiserror::Error; - -pub type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum YanixError { - #[error("raw os error {0}")] - Errno(#[from] Errno), - #[error("a nul byte was not found in the expected position")] - NulError(#[from] ffi::NulError), - #[error("integral type conversion failed")] - TryFromIntError(#[from] num::TryFromIntError), -} +pub use error::Error; +pub type Result = std::result::Result; diff --git a/crates/wasi-common/yanix/src/poll.rs b/crates/wasi-common/yanix/src/poll.rs index db33b584b4..315956bc3e 100644 --- a/crates/wasi-common/yanix/src/poll.rs +++ b/crates/wasi-common/yanix/src/poll.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use bitflags::bitflags; use std::{convert::TryInto, os::unix::prelude::*}; @@ -36,7 +36,7 @@ impl PollFd { } pub fn poll(fds: &mut [PollFd], timeout: libc::c_int) -> Result { - Errno::from_result(unsafe { + Error::from_result(unsafe { libc::poll( fds.as_mut_ptr() as *mut libc::pollfd, fds.len() as libc::nfds_t, diff --git a/crates/wasi-common/yanix/src/socket.rs b/crates/wasi-common/yanix/src/socket.rs index f0f1364e13..22e5d488f1 100644 --- a/crates/wasi-common/yanix/src/socket.rs +++ b/crates/wasi-common/yanix/src/socket.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use std::os::unix::prelude::*; #[derive(Debug, Clone, Copy)] @@ -15,7 +15,7 @@ pub unsafe fn get_socket_type(fd: RawFd) -> Result { use std::mem::{self, MaybeUninit}; let mut buffer = MaybeUninit::::zeroed().assume_init(); let mut out_len = mem::size_of::() as libc::socklen_t; - Errno::from_success_code(libc::getsockopt( + Error::from_success_code(libc::getsockopt( fd, libc::SOL_SOCKET, libc::SO_TYPE, diff --git a/crates/wasi-common/yanix/src/sys/bsd/dir.rs b/crates/wasi-common/yanix/src/sys/bsd/dir.rs index 2a0b4b3a0e..adc55ce2a2 100644 --- a/crates/wasi-common/yanix/src/sys/bsd/dir.rs +++ b/crates/wasi-common/yanix/src/sys/bsd/dir.rs @@ -1,8 +1,8 @@ use crate::{ dir::{Dir, Entry, EntryExt, SeekLoc}, - Errno, Result, + Result, }; -use std::ops::Deref; +use std::{io, ops::Deref}; #[derive(Copy, Clone, Debug)] pub(crate) struct EntryImpl { @@ -19,16 +19,17 @@ impl Deref for EntryImpl { } pub(crate) fn iter_impl(dir: &Dir) -> Option> { - let errno = Errno::last(); + let errno = io::Error::last_os_error(); let dirent = unsafe { libc::readdir(dir.as_raw().as_ptr()) }; if dirent.is_null() { - if errno != Errno::last() { + let curr_errno = io::Error::last_os_error(); + if errno.raw_os_error() != curr_errno.raw_os_error() { // TODO This should be verified on different BSD-flavours. // // According to 4.3BSD/POSIX.1-2001 man pages, there was an error // if the errno value has changed at some point during the sequence // of readdir calls. - Some(Err(Errno::last().into())) + Some(Err(curr_errno.into())) } else { // Not an error. We've simply reached the end of the stream. None diff --git a/crates/wasi-common/yanix/src/sys/bsd/fadvise.rs b/crates/wasi-common/yanix/src/sys/bsd/fadvise.rs index 0f60dcfb32..97baca65a3 100644 --- a/crates/wasi-common/yanix/src/sys/bsd/fadvise.rs +++ b/crates/wasi-common/yanix/src/sys/bsd/fadvise.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use std::{convert::TryInto, os::unix::prelude::*}; #[cfg(not(any(target_os = "freebsd", target_os = "netbsd")))] @@ -48,7 +48,7 @@ pub unsafe fn posix_fadvise( ra_offset: offset, ra_count: len.try_into()?, }; - Errno::from_success_code(libc::fcntl(fd, libc::F_RDADVISE, &advisory)) + Error::from_success_code(libc::fcntl(fd, libc::F_RDADVISE, &advisory)) } #[cfg(any(target_os = "freebsd", target_os = "netbsd"))] @@ -58,7 +58,7 @@ pub unsafe fn posix_fadvise( len: libc::off_t, advice: PosixFadviseAdvice, ) -> Result<()> { - Errno::from_success_code(libc::posix_fadvise(fd, offset, len, advice as libc::c_int)) + Error::from_success_code(libc::posix_fadvise(fd, offset, len, advice as libc::c_int)) } // On BSDs without support we leave it as no-op diff --git a/crates/wasi-common/yanix/src/sys/bsd/file.rs b/crates/wasi-common/yanix/src/sys/bsd/file.rs index b367154812..e17355d968 100644 --- a/crates/wasi-common/yanix/src/sys/bsd/file.rs +++ b/crates/wasi-common/yanix/src/sys/bsd/file.rs @@ -1,5 +1,5 @@ -use crate::{Errno, Result}; -use std::os::unix::prelude::*; +use crate::Result; +use std::{io, os::unix::prelude::*}; pub unsafe fn isatty(fd: RawFd) -> Result { let res = libc::isatty(fd); @@ -8,9 +8,13 @@ pub unsafe fn isatty(fd: RawFd) -> Result { Ok(true) } else { // ... otherwise 0 is returned, and errno is set to indicate the error. - let errno = Errno::last(); - if errno == Errno::ENOTTY { - Ok(false) + let errno = io::Error::last_os_error(); + if let Some(raw_errno) = errno.raw_os_error() { + if raw_errno == libc::ENOTTY { + Ok(false) + } else { + Err(errno.into()) + } } else { Err(errno.into()) } diff --git a/crates/wasi-common/yanix/src/sys/linux/dir.rs b/crates/wasi-common/yanix/src/sys/linux/dir.rs index aa2598f070..9fc3ce1bab 100644 --- a/crates/wasi-common/yanix/src/sys/linux/dir.rs +++ b/crates/wasi-common/yanix/src/sys/linux/dir.rs @@ -1,8 +1,8 @@ use crate::{ dir::{Dir, Entry, EntryExt, SeekLoc}, - Errno, Result, + Result, }; -use std::ops::Deref; +use std::{io, ops::Deref}; #[derive(Copy, Clone, Debug)] pub(crate) struct EntryImpl(libc::dirent64); @@ -26,16 +26,17 @@ impl EntryExt for Entry { } pub(crate) fn iter_impl(dir: &Dir) -> Option> { - let errno = Errno::last(); + let errno = io::Error::last_os_error(); let dirent = unsafe { libc::readdir64(dir.as_raw().as_ptr()) }; if dirent.is_null() { - if errno != Errno::last() { + let curr_errno = io::Error::last_os_error(); + if errno.raw_os_error() != curr_errno.raw_os_error() { // TODO This should be verified on different BSD-flavours. // // According to 4.3BSD/POSIX.1-2001 man pages, there was an error // if the errno value has changed at some point during the sequence // of readdir calls. - Some(Err(Errno::last().into())) + Some(Err(curr_errno.into())) } else { // Not an error. We've simply reached the end of the stream. None diff --git a/crates/wasi-common/yanix/src/sys/linux/fadvise.rs b/crates/wasi-common/yanix/src/sys/linux/fadvise.rs index 999525e1c7..fc2c60c70e 100644 --- a/crates/wasi-common/yanix/src/sys/linux/fadvise.rs +++ b/crates/wasi-common/yanix/src/sys/linux/fadvise.rs @@ -1,4 +1,4 @@ -use crate::{Errno, Result}; +use crate::{Error, Result}; use std::os::unix::prelude::*; #[derive(Debug, Copy, Clone)] @@ -18,5 +18,5 @@ pub unsafe fn posix_fadvise( len: libc::off_t, advice: PosixFadviseAdvice, ) -> Result<()> { - Errno::from_success_code(libc::posix_fadvise(fd, offset, len, advice as libc::c_int)) + Error::from_success_code(libc::posix_fadvise(fd, offset, len, advice as libc::c_int)) } diff --git a/crates/wasi-common/yanix/src/sys/linux/file.rs b/crates/wasi-common/yanix/src/sys/linux/file.rs index c5f88f457b..98798b7999 100644 --- a/crates/wasi-common/yanix/src/sys/linux/file.rs +++ b/crates/wasi-common/yanix/src/sys/linux/file.rs @@ -1,5 +1,5 @@ -use crate::{Errno, Result}; -use std::os::unix::prelude::*; +use crate::Result; +use std::{io, os::unix::prelude::*}; pub unsafe fn isatty(fd: RawFd) -> Result { let res = libc::isatty(fd); @@ -8,14 +8,18 @@ pub unsafe fn isatty(fd: RawFd) -> Result { Ok(true) } else { // ... otherwise 0 is returned, and errno is set to indicate the error. - let errno = Errno::last(); - // While POSIX specifies ENOTTY if the passed - // fd is *not* a tty, on Linux, some implementations - // may return EINVAL instead. - // - // https://linux.die.net/man/3/isatty - if errno == Errno::ENOTTY || errno == Errno::EINVAL { - Ok(false) + let errno = io::Error::last_os_error(); + if let Some(raw_errno) = errno.raw_os_error() { + // While POSIX specifies ENOTTY if the passed + // fd is *not* a tty, on Linux, some implementations + // may return EINVAL instead. + // + // https://linux.die.net/man/3/isatty + if raw_errno == libc::ENOTTY || raw_errno == libc::EINVAL { + Ok(false) + } else { + Err(errno.into()) + } } else { Err(errno.into()) }