From cd944bde6d28b241350d83a89aa656953222aba7 Mon Sep 17 00:00:00 2001 From: xtqqczze <45661989+xtqqczze@users.noreply.github.com> Date: Thu, 3 Sep 2026 17:42:21 +0100 Subject: [PATCH] Add support for Hermit OS --- src/backend/libc/io/errno.rs | 2 +- src/backend/libc/io/syscalls.rs | 19 +++++++++++----- src/backend/libc/io/types.rs | 1 + src/io/dup.rs | 3 ++- src/io/fcntl.rs | 4 +++- src/io/ioctl.rs | 7 +++++- src/io/read_write.rs | 6 +++-- src/ioctl/mod.rs | 1 + src/lib.rs | 10 ++++++++- src/maybe_polyfill/no_std/os/fd/owned.rs | 28 ++++++++++++++++++++---- src/maybe_polyfill/no_std/os/mod.rs | 2 +- src/maybe_polyfill/std/mod.rs | 7 +++++- tests/backends.rs | 2 +- tests/io/ioctl.rs | 7 +++++- 14 files changed, 78 insertions(+), 21 deletions(-) diff --git a/src/backend/libc/io/errno.rs b/src/backend/libc/io/errno.rs index 81f0e4893..252afec5e 100644 --- a/src/backend/libc/io/errno.rs +++ b/src/backend/libc/io/errno.rs @@ -791,7 +791,7 @@ impl Errno { #[cfg(not(target_os = "l4re"))] pub const NOTSOCK: Self = Self(c::ENOTSOCK); /// `ENOTSUP` - #[cfg(not(any(windows, target_os = "redox")))] + #[cfg(not(any(windows, target_os = "hermit", target_os = "redox")))] pub const NOTSUP: Self = Self(c::ENOTSUP); /// `ENOTTY` #[cfg(not(windows))] diff --git a/src/backend/libc/io/syscalls.rs b/src/backend/libc/io/syscalls.rs index 46f7c5859..0b37bfe22 100644 --- a/src/backend/libc/io/syscalls.rs +++ b/src/backend/libc/io/syscalls.rs @@ -43,6 +43,7 @@ pub(crate) fn write(fd: BorrowedFd<'_>, buf: &[u8]) -> io::Result { } } +#[cfg(not(target_os = "hermit"))] pub(crate) unsafe fn pread( fd: BorrowedFd<'_>, buf: (*mut u8, usize), @@ -59,6 +60,7 @@ pub(crate) unsafe fn pread( ret_usize(c::pread(borrowed_fd(fd), buf.0.cast(), len, offset)) } +#[cfg(not(target_os = "hermit"))] pub(crate) fn pwrite(fd: BorrowedFd<'_>, buf: &[u8], offset: u64) -> io::Result { let len = min(buf.len(), READ_LIMIT); @@ -76,8 +78,8 @@ pub(crate) fn readv(fd: BorrowedFd<'_>, bufs: &mut [IoSliceMut<'_>]) -> io::Resu unsafe { ret_usize(c::readv( borrowed_fd(fd), - bufs.as_ptr().cast::(), - min(bufs.len(), MAX_IOV) as c::c_int, + bufs.as_ptr().cast(), + min(bufs.len(), MAX_IOV) as _, )) } } @@ -87,8 +89,8 @@ pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result(), - min(bufs.len(), MAX_IOV) as c::c_int, + bufs.as_ptr().cast(), + min(bufs.len(), MAX_IOV) as _, )) } } @@ -97,6 +99,7 @@ pub(crate) fn writev(fd: BorrowedFd<'_>, bufs: &[IoSlice<'_>]) -> io::Result) -> io::Result { let flags = unsafe { ret_c_int(c::fcntl(borrowed_fd(fd), c::F_GETFD))? }; Ok(FdFlags::from_bits_retain(bitcast!(flags))) } +#[cfg(not(target_os = "hermit"))] pub(crate) fn fcntl_setfd(fd: BorrowedFd<'_>, flags: FdFlags) -> io::Result<()> { unsafe { ret(c::fcntl(borrowed_fd(fd), c::F_SETFD, flags.bits())) } } -#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[cfg(not(any(target_os = "espidf", target_os = "hermit", target_os = "wasi")))] pub(crate) fn fcntl_dupfd_cloexec(fd: BorrowedFd<'_>, min: RawFd) -> io::Result { unsafe { ret_owned_fd(c::fcntl(borrowed_fd(fd), c::F_DUPFD_CLOEXEC, min)) } } @@ -259,7 +265,7 @@ pub(crate) fn dup(fd: BorrowedFd<'_>) -> io::Result { } #[allow(clippy::needless_pass_by_ref_mut)] -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "hermit", target_os = "wasi")))] pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { unsafe { ret_discarded_fd(c::dup2(borrowed_fd(fd), borrowed_fd(new.as_fd()))) } } @@ -272,6 +278,7 @@ pub(crate) fn dup2(fd: BorrowedFd<'_>, new: &mut OwnedFd) -> io::Result<()> { target_os = "dragonfly", target_os = "espidf", target_os = "haiku", + target_os = "hermit", target_os = "horizon", target_os = "nto", target_os = "redox", diff --git a/src/backend/libc/io/types.rs b/src/backend/libc/io/types.rs index b434b68af..9c376942b 100644 --- a/src/backend/libc/io/types.rs +++ b/src/backend/libc/io/types.rs @@ -55,6 +55,7 @@ bitflags! { apple, target_os = "aix", target_os = "android", + target_os = "hermit", target_os = "redox", )))] // Android 5.0 has dup3, but libc doesn't have bindings const CLOEXEC = bitcast!(c::O_CLOEXEC); diff --git a/src/io/dup.rs b/src/io/dup.rs index 1d1a4852d..6df4bfd6e 100644 --- a/src/io/dup.rs +++ b/src/io/dup.rs @@ -84,7 +84,7 @@ pub fn dup(fd: Fd) -> io::Result { /// [`stdio::dup2_stdin`]: crate::stdio::dup2_stdin /// [`stdio::dup2_stdout`]: crate::stdio::dup2_stdout /// [`stdio::dup2_stderr`]: crate::stdio::dup2_stderr -#[cfg(not(target_os = "wasi"))] +#[cfg(not(any(target_os = "hermit", target_os = "wasi")))] #[inline] pub fn dup2(fd: Fd, new: &mut OwnedFd) -> io::Result<()> { backend::io::syscalls::dup2(fd.as_fd(), new) @@ -114,6 +114,7 @@ pub fn dup2(fd: Fd, new: &mut OwnedFd) -> io::Result<()> { #[cfg(not(any( target_os = "aix", target_os = "espidf", + target_os = "hermit", target_os = "horizon", target_os = "nto", target_os = "vita", diff --git a/src/io/fcntl.rs b/src/io/fcntl.rs index fcb63a3ba..b09b31ffd 100644 --- a/src/io/fcntl.rs +++ b/src/io/fcntl.rs @@ -35,6 +35,7 @@ pub use backend::io::types::FdFlags; /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 /// [illumos]: https://illumos.org/man/2/fcntl /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Control-Operations.html#index-fcntl-function +#[cfg(not(target_os = "hermit"))] #[inline] #[doc(alias = "F_GETFD")] pub fn fcntl_getfd(fd: Fd) -> io::Result { @@ -63,6 +64,7 @@ pub fn fcntl_getfd(fd: Fd) -> io::Result { /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=fcntl§ion=2 /// [illumos]: https://illumos.org/man/2/fcntl /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Control-Operations.html#index-fcntl-function +#[cfg(not(target_os = "hermit"))] #[inline] #[doc(alias = "F_SETFD")] pub fn fcntl_setfd(fd: Fd, flags: FdFlags) -> io::Result<()> { @@ -99,7 +101,7 @@ pub fn fcntl_setfd(fd: Fd, flags: FdFlags) -> io::Result<()> { /// [illumos]: https://illumos.org/man/2/fcntl /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/Control-Operations.html#index-fcntl-function /// [file description]: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap03.html#tag_03_258 -#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] +#[cfg(not(any(target_os = "espidf", target_os = "hermit", target_os = "wasi")))] #[inline] #[doc(alias = "F_DUPFD_CLOEXEC")] pub fn fcntl_dupfd_cloexec(fd: Fd, min: RawFd) -> io::Result { diff --git a/src/io/ioctl.rs b/src/io/ioctl.rs index 33bf07cf5..52c125030 100644 --- a/src/io/ioctl.rs +++ b/src/io/ioctl.rs @@ -86,7 +86,12 @@ pub fn ioctl_fionbio(fd: Fd, value: bool) -> io::Result<()> { /// [FreeBSD]: https://man.freebsd.org/cgi/man.cgi?query=ioctl&sektion=2#GENERIC%09IOCTLS /// [NetBSD]: https://man.netbsd.org/ioctl.2#GENERIC%20IOCTLS /// [OpenBSD]: https://man.openbsd.org/ioctl.2#GENERIC_IOCTLS -#[cfg(not(any(target_os = "espidf", target_os = "horizon", target_os = "vita")))] +#[cfg(not(any( + target_os = "espidf", + target_os = "hermit", + target_os = "horizon", + target_os = "vita" +)))] #[inline] #[doc(alias = "FIONREAD")] pub fn ioctl_fionread(fd: Fd) -> io::Result { diff --git a/src/io/read_write.rs b/src/io/read_write.rs index 0e0969103..aeeb1f84c 100644 --- a/src/io/read_write.rs +++ b/src/io/read_write.rs @@ -92,7 +92,7 @@ pub fn write(fd: Fd, buf: &[u8]) -> io::Result { /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pread§ion=2 /// [illumos]: https://illumos.org/man/2/pread /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-pread64 -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "hermit")))] #[inline] pub fn pread>( fd: Fd, @@ -131,7 +131,7 @@ pub fn pread>( /// [DragonFly BSD]: https://man.dragonflybsd.org/?command=pwrite§ion=2 /// [illumos]: https://illumos.org/man/2/pwrite /// [glibc]: https://sourceware.org/glibc/manual/latest/html_node/I_002fO-Primitives.html#index-pwrite64 -#[cfg(not(windows))] +#[cfg(not(any(windows, target_os = "hermit")))] #[inline] pub fn pwrite(fd: Fd, buf: &[u8], offset: u64) -> io::Result { backend::io::syscalls::pwrite(fd.as_fd(), buf, offset) @@ -217,6 +217,7 @@ pub fn writev(fd: Fd, bufs: &[IoSlice<'_>]) -> io::Result { target_os = "cygwin", target_os = "espidf", target_os = "haiku", + target_os = "hermit", target_os = "horizon", target_os = "nto", target_os = "redox", @@ -256,6 +257,7 @@ pub fn preadv(fd: Fd, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io: target_os = "cygwin", target_os = "espidf", target_os = "haiku", + target_os = "hermit", target_os = "horizon", target_os = "nto", target_os = "redox", diff --git a/src/ioctl/mod.rs b/src/ioctl/mod.rs index 70c690530..a2d62d46b 100644 --- a/src/ioctl/mod.rs +++ b/src/ioctl/mod.rs @@ -330,6 +330,7 @@ type _Opcode = c::c_ulong; target_os = "aix", target_os = "cygwin", target_os = "fuchsia", + target_os = "hermit", target_os = "emscripten", target_os = "nto", target_os = "wasi", diff --git a/src/lib.rs b/src/lib.rs index 8109ca2bb..3c2e5930c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -185,7 +185,15 @@ pub(crate) mod msan; // versions of libc and not others. #[cfg(any( all(linux_raw, feature = "use-libc-auxv"), - all(libc, not(any(windows, target_os = "espidf", target_os = "wasi"))) + all( + libc, + not(any( + windows, + target_os = "espidf", + target_os = "hermit", + target_os = "wasi" + )) + ) ))] #[macro_use] mod weak; diff --git a/src/maybe_polyfill/no_std/os/fd/owned.rs b/src/maybe_polyfill/no_std/os/fd/owned.rs index ca9b05f31..c3991fbd0 100644 --- a/src/maybe_polyfill/no_std/os/fd/owned.rs +++ b/src/maybe_polyfill/no_std/os/fd/owned.rs @@ -101,7 +101,12 @@ impl BorrowedFd<'_> { impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file handle /// as the existing `OwnedFd` instance. - #[cfg(not(target_arch = "wasm32"))] + #[cfg(not(any( + target_os = "hermit", + target_os = "motor", + target_os = "trusty", + target_os = "wasi" + )))] pub fn try_clone(&self) -> crate::io::Result { // We want to atomically duplicate this file descriptor and set the // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This @@ -121,7 +126,12 @@ impl OwnedFd { /// Creates a new `OwnedFd` instance that shares the same underlying file handle /// as the existing `OwnedFd` instance. - #[cfg(target_arch = "wasm32")] + #[cfg(any( + target_os = "hermit", + target_os = "motor", + target_os = "trusty", + target_os = "wasi" + ))] pub fn try_clone(&self) -> crate::io::Result { Err(crate::io::Errno::NOSYS) } @@ -130,7 +140,12 @@ impl OwnedFd { impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(not(any(target_arch = "wasm32", target_os = "hermit")))] + #[cfg(not(any( + target_os = "hermit", + target_os = "motor", + target_os = "trusty", + target_os = "wasi" + )))] #[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))] pub fn try_clone_to_owned(&self) -> crate::io::Result { // Avoid using file descriptors below 3 as they are used for stdio @@ -153,7 +168,12 @@ impl BorrowedFd<'_> { /// Creates a new `OwnedFd` instance that shares the same underlying file /// description as the existing `BorrowedFd` instance. - #[cfg(any(target_arch = "wasm32", target_os = "hermit"))] + #[cfg(any( + target_os = "hermit", + target_os = "motor", + target_os = "trusty", + target_os = "wasi" + ))] #[cfg_attr(staged_api, stable(feature = "io_safety", since = "1.63.0"))] pub fn try_clone_to_owned(&self) -> crate::io::Result { Err(crate::io::Errno::NOSYS) diff --git a/src/maybe_polyfill/no_std/os/mod.rs b/src/maybe_polyfill/no_std/os/mod.rs index 67f41f5b3..29d55c747 100644 --- a/src/maybe_polyfill/no_std/os/mod.rs +++ b/src/maybe_polyfill/no_std/os/mod.rs @@ -1,4 +1,4 @@ -#[cfg(any(unix, target_os = "wasi"))] +#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))] pub mod fd; #[cfg(windows)] pub mod windows; diff --git a/src/maybe_polyfill/std/mod.rs b/src/maybe_polyfill/std/mod.rs index 17b280959..41a126b38 100644 --- a/src/maybe_polyfill/std/mod.rs +++ b/src/maybe_polyfill/std/mod.rs @@ -21,7 +21,12 @@ pub mod os { pub mod fd { // Change to use `std::os::fd` when MSRV becomes Rust 1.66 or higher. - #[cfg(target_os = "wasi")] + #[cfg(any( + target_os = "hermit", + target_os = "motor", + target_os = "trusty", + target_os = "wasi" + ))] pub use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; #[cfg(unix)] pub use std::os::unix::io::{ diff --git a/tests/backends.rs b/tests/backends.rs index 3ded514ff..b6c9435d6 100644 --- a/tests/backends.rs +++ b/tests/backends.rs @@ -82,7 +82,7 @@ fn test_backends() { #[cfg(windows)] let libc_dep = "windows-sys"; - #[cfg(any(unix, target_os = "wasi"))] + #[cfg(not(windows))] let libc_dep = "libc"; // Test the use-libc crate, which enables the "use-libc" cargo feature. diff --git a/tests/io/ioctl.rs b/tests/io/ioctl.rs index 77b0a76f0..e6c3d3900 100644 --- a/tests/io/ioctl.rs +++ b/tests/io/ioctl.rs @@ -1,5 +1,10 @@ // `ioctl_fionread` on Windows doesn't work on files. -#[cfg(not(any(windows, target_os = "cygwin", target_os = "haiku")))] +#[cfg(not(any( + windows, + target_os = "cygwin", + target_os = "hermit", + target_os = "haiku" +)))] #[test] fn test_ioctls() { let file = std::fs::File::open("Cargo.toml").unwrap();