#![cfg_attr(not(feature = "std"), no_std)]
use self::error::{Error, Result};
pub mod error {
use super::*;
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Error {
errno: u16,
}
impl Error {
pub fn new(errno: i32) -> Self {
Self {
errno: errno.try_into().unwrap_or(u16::MAX),
}
}
pub fn errno(self) -> i32 {
self.errno.into()
}
pub fn is_wouldblock(self) -> bool {
matches!(self.errno(), errno::EAGAIN | errno::EWOULDBLOCK)
}
pub fn is_interrupt(self) -> bool {
self.errno() == errno::EINTR
}
pub fn mux(res: Result<usize, Self>) -> usize {
match res {
Ok(success) => success,
Err(error) => usize::wrapping_neg(usize::from(error.errno)),
}
}
pub fn demux(res: usize) -> Result<usize, Self> {
if res > usize::wrapping_neg(4096) {
Err(Self {
errno: res.wrapping_neg().try_into().expect("2^BITS - res < 4096"),
})
} else {
Ok(res)
}
}
pub fn description(&self) -> &'static str {
syscall::error::STR_ERROR
.get(usize::from(self.errno))
.copied()
.unwrap_or("Unknown")
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.description())
}
}
impl core::fmt::Debug for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "Error `{}` {}", self.description(), self.errno)
}
}
#[cfg(feature = "redox_syscall_exports")]
impl From<syscall::Error> for Error {
fn from(value: syscall::Error) -> Self {
Self {
errno: value.errno.try_into().unwrap_or(u16::MAX),
}
}
}
#[cfg(feature = "std")]
impl From<Error> for std::io::Error {
fn from(value: Error) -> Self {
Self::from_raw_os_error(value.errno.into())
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
pub type Result<T, E = Error> = core::result::Result<T, E>;
}
pub mod flag {
pub use libc::{
O_ACCMODE, O_APPEND, O_ASYNC, O_CLOEXEC, O_CREAT, O_DIRECTORY, O_EXCL, O_FSYNC, O_NOFOLLOW,
O_NONBLOCK, O_PATH, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
};
pub use libc::{CLOCK_MONOTONIC, CLOCK_REALTIME};
pub use libc::{SIG_BLOCK, SIG_SETMASK, SIG_UNBLOCK};
pub use libc::{
SIGABRT,
SIGALRM,
SIGBUS,
SIGCHLD,
SIGCONT,
SIGFPE,
SIGHUP,
SIGILL,
SIGINT,
SIGIO,
SIGKILL,
SIGPIPE,
SIGPROF,
SIGPWR,
SIGQUIT,
SIGSEGV,
SIGSTKFLT,
SIGSYS,
SIGTERM,
SIGTRAP,
SIGTSTP,
SIGTTIN,
SIGTTOU,
SIGURG,
SIGUSR1,
SIGUSR2,
SIGVTALRM,
SIGWINCH,
SIGXFSZ,
};
#[cfg(target_os = "redox")]
pub use libc::{O_EXLOCK, O_SHLOCK, O_SYMLINK};
pub const MAP_SHARED: u32 = libc::MAP_SHARED as u32;
pub const MAP_PRIVATE: u32 = libc::MAP_PRIVATE as u32;
pub const PROT_NONE: u32 = libc::PROT_NONE as u32;
pub const PROT_READ: u32 = libc::PROT_READ as u32;
pub const PROT_WRITE: u32 = libc::PROT_WRITE as u32;
pub const PROT_EXEC: u32 = libc::PROT_EXEC as u32;
}
pub mod errno {
pub use libc::{
E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, EADV, EAFNOSUPPORT, EAGAIN, EALREADY, EBADE,
EBADF, EBADFD, EBADMSG, EBADR, EBADRQC, EBADSLT, EBFONT, EBUSY, ECANCELED, ECHILD, ECHRNG,
ECOMM, ECONNABORTED, ECONNREFUSED, ECONNRESET, EDEADLK, EDEADLOCK, EDESTADDRREQ, EDOM,
EDOTDOT, EDQUOT, EEXIST, EFAULT, EFBIG, EHOSTDOWN, EHOSTUNREACH, EIDRM, EILSEQ,
EINPROGRESS, EINTR, EINVAL, EIO, EISCONN, EISDIR, EISNAM, EKEYEXPIRED, EKEYREJECTED,
EKEYREVOKED, EL2HLT, EL2NSYNC, EL3HLT, EL3RST, ELIBACC, ELIBBAD, ELIBEXEC, ELIBMAX,
ELIBSCN, ELNRNG, ELOOP, EMEDIUMTYPE, EMFILE, EMLINK, EMSGSIZE, EMULTIHOP, ENAMETOOLONG,
ENAVAIL, ENETDOWN, ENETRESET, ENETUNREACH, ENFILE, ENOANO, ENOBUFS, ENOCSI, ENODEV, ENOENT,
ENOEXEC, ENOKEY, ENOLCK, ENOMEDIUM, ENOMEM, ENOMSG, ENONET, ENOPKG, ENOPROTOOPT, ENOSPC,
ENOSR, ENOSTR, ENOSYS, ENOTBLK, ENOTCONN, ENOTDIR, ENOTEMPTY, ENOTNAM, ENOTRECOVERABLE,
ENOTSOCK, ENOTTY, ENOTUNIQ, ENXIO, EOPNOTSUPP, EOVERFLOW, EOWNERDEAD, EPERM, EPFNOSUPPORT,
EPIPE, EPROTO, EPROTONOSUPPORT, EPROTOTYPE, ERANGE, EREMCHG, EREMOTE, EREMOTEIO, ERESTART,
EROFS, ESHUTDOWN, ESOCKTNOSUPPORT, ESPIPE, ESRCH, ESRMNT, ESTALE, ESTRPIPE, ETIME,
ETIMEDOUT, ETOOMANYREFS, ETXTBSY, EUCLEAN, EUNATCH, EUSERS, EWOULDBLOCK, EXDEV, EXFULL,
};
}
pub mod data {
pub use libc::sigaction as SigAction;
pub use libc::stat as Stat;
pub use libc::statvfs as StatVfs;
pub use libc::timespec as TimeSpec;
pub fn timespec_from_mut_bytes(bytes: &mut [u8]) -> &mut TimeSpec {
assert!(bytes.len() >= core::mem::size_of::<TimeSpec>());
assert_eq!(
bytes.as_ptr() as usize % core::mem::align_of::<TimeSpec>(),
0
);
unsafe { &mut *bytes.as_mut_ptr().cast() }
}
pub fn timespec_from_bytes(bytes: &[u8]) -> &TimeSpec {
assert!(bytes.len() >= core::mem::size_of::<TimeSpec>());
assert_eq!(
bytes.as_ptr() as usize % core::mem::align_of::<TimeSpec>(),
0
);
unsafe { &*bytes.as_ptr().cast() }
}
#[cfg(target_os = "redox")]
pub use libc::sigset_t as SigSet;
#[cfg(not(target_os = "redox"))]
pub type SigSet = u64;
}
type RawResult = usize;
extern "C" {
fn redox_open_v1(path_base: *const u8, path_len: usize, flags: u32, mode: u16) -> RawResult;
fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> RawResult;
fn redox_dup2_v1(old_fd: usize, new_fd: usize, buf: *const u8, len: usize) -> RawResult;
fn redox_read_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult;
fn redox_write_v1(fd: usize, src_base: *const u8, src_len: usize) -> RawResult;
fn redox_fsync_v1(fd: usize) -> RawResult;
fn redox_fdatasync_v1(fd: usize) -> RawResult;
fn redox_fchmod_v1(fd: usize, new_mode: u16) -> RawResult;
fn redox_fchown_v1(fd: usize, new_uid: u32, new_gid: u32) -> RawResult;
fn redox_fpath_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult;
fn redox_fstat_v1(fd: usize, dst: *mut data::Stat) -> RawResult;
fn redox_fstatvfs_v1(fd: usize, dst: *mut data::StatVfs) -> RawResult;
fn redox_futimens_v1(fd: usize, times: *const data::TimeSpec) -> RawResult;
fn redox_close_v1(fd: usize) -> RawResult;
fn redox_get_pid_v1() -> RawResult;
fn redox_get_euid_v1() -> RawResult;
fn redox_get_ruid_v1() -> RawResult;
fn redox_get_egid_v1() -> RawResult;
fn redox_get_rgid_v1() -> RawResult;
fn redox_setrens_v1(rns: usize, ens: usize) -> RawResult;
fn redox_kill_v1(pid: usize, signal: u32) -> RawResult;
fn redox_waitpid_v1(pid: usize, status: *mut i32, options: u32) -> RawResult;
fn redox_sigprocmask_v1(how: u32, new: *const u64, old: *mut u64) -> RawResult;
fn redox_sigaction_v1(
signal: u32,
new: *const data::SigAction,
old: *mut data::SigAction,
) -> RawResult;
fn redox_clock_gettime_v1(clock: usize, ts: *mut data::TimeSpec) -> RawResult;
fn redox_mmap_v1(
addr: *mut (),
unaligned_len: usize,
prot: u32,
flags: u32,
fd: usize,
offset: u64,
) -> RawResult;
fn redox_munmap_v1(addr: *mut (), unaligned_len: usize) -> RawResult;
}
#[cfg(feature = "call")]
pub struct Fd(usize);
#[cfg(feature = "call")]
impl Fd {
#[inline]
pub fn open(path: &str, flags: i32, mode: u16) -> Result<Self> {
Ok(Self(call::open(path, flags, mode)?))
}
#[inline]
pub fn dup(&self, buf: &[u8]) -> Result<usize> {
call::dup(self.raw(), buf)
}
#[inline]
pub fn dup2(&self, new_fd: usize, buf: &[u8]) -> Result<usize> {
call::dup2(self.raw(), new_fd, buf)
}
#[inline]
pub const fn raw(&self) -> usize {
self.0
}
#[inline]
pub fn into_raw(self) -> usize {
let raw = self.raw();
core::mem::forget(self);
raw
}
#[inline]
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
call::read(self.raw(), buf)
}
#[inline]
pub fn write(&self, buf: &[u8]) -> Result<usize> {
call::write(self.raw(), buf)
}
#[inline]
pub fn fpath(&self, path: &mut [u8]) -> Result<usize> {
call::fpath(self.raw(), path)
}
#[inline]
pub fn fsync(&self) -> Result<()> {
call::fsync(self.raw())
}
#[inline]
pub fn fdatasync(&self) -> Result<()> {
call::fdatasync(self.raw())
}
#[inline]
pub fn chmod(&self, new_mode: u16) -> Result<()> {
call::fchmod(self.raw(), new_mode)
}
#[inline]
pub fn chown(&self, new_uid: u32, new_gid: u32) -> Result<()> {
call::fchown(self.raw(), new_uid, new_gid)
}
pub fn stat(&self) -> Result<data::Stat> {
call::fstat(self.raw())
}
pub fn statvfs(&self) -> Result<data::StatVfs> {
call::fstatvfs(self.raw())
}
#[inline]
pub fn close(self) -> Result<()> {
call::close(self.into_raw())
}
}
#[cfg(feature = "call")]
impl Drop for Fd {
fn drop(&mut self) {
let _ = unsafe { redox_close_v1(self.0) };
}
}
#[cfg(feature = "call")]
pub mod call {
use core::mem::MaybeUninit;
use super::*;
#[inline]
pub fn open(path: impl AsRef<str>, flags: i32, mode: u16) -> Result<usize> {
let path = path.as_ref();
Ok(Error::demux(unsafe {
redox_open_v1(path.as_ptr(), path.len(), flags as u32, mode)
})?)
}
#[inline]
pub fn dup(fd: usize, buf: impl AsRef<[u8]>) -> Result<usize> {
let buf = buf.as_ref();
Ok(Error::demux(unsafe {
redox_dup_v1(fd, buf.as_ptr(), buf.len())
})?)
}
#[inline]
pub fn dup2(old_fd: usize, new_fd: usize, buf: impl AsRef<[u8]>) -> Result<usize> {
let buf = buf.as_ref();
Ok(Error::demux(unsafe {
redox_dup2_v1(old_fd, new_fd, buf.as_ptr(), buf.len())
})?)
}
#[inline]
pub fn read(raw_fd: usize, buf: &mut [u8]) -> Result<usize> {
Ok(Error::demux(unsafe {
redox_read_v1(raw_fd, buf.as_mut_ptr(), buf.len())
})?)
}
#[inline]
pub fn write(raw_fd: usize, buf: &[u8]) -> Result<usize> {
Error::demux(unsafe { redox_write_v1(raw_fd, buf.as_ptr(), buf.len()) })
}
#[inline]
pub fn fsync(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_fsync_v1(raw_fd) }).map(|_| ())
}
#[inline]
pub fn fdatasync(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_fdatasync_v1(raw_fd) }).map(|_| ())
}
#[inline]
pub fn fchmod(raw_fd: usize, new_mode: u16) -> Result<()> {
Error::demux(unsafe { redox_fchmod_v1(raw_fd, new_mode) })?;
Ok(())
}
#[inline]
pub fn fchown(raw_fd: usize, new_uid: u32, new_gid: u32) -> Result<()> {
Error::demux(unsafe { redox_fchown_v1(raw_fd, new_uid, new_gid) })?;
Ok(())
}
#[inline]
pub fn fpath(raw_fd: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_fpath_v1(raw_fd, buf.as_mut_ptr(), buf.len()) })
}
#[inline]
pub fn fstat(raw_fd: usize) -> Result<data::Stat> {
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_fstat_v1(raw_fd, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
}
}
#[inline]
pub fn fstatvfs(raw_fd: usize) -> Result<data::StatVfs> {
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_fstatvfs_v1(raw_fd, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
}
}
#[inline]
pub fn futimens(raw_fd: usize, times: &[data::TimeSpec; 2]) -> Result<()> {
Error::demux(unsafe { redox_futimens_v1(raw_fd, times.as_ptr()) })?;
Ok(())
}
#[inline]
pub fn close(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_close_v1(raw_fd) })?;
Ok(())
}
#[inline]
pub fn geteuid() -> Result<usize> {
Error::demux(unsafe { redox_get_euid_v1() })
}
#[inline]
pub fn getruid() -> Result<usize> {
Error::demux(unsafe { redox_get_ruid_v1() })
}
#[inline]
pub fn getegid() -> Result<usize> {
Error::demux(unsafe { redox_get_egid_v1() })
}
#[inline]
pub fn getrgid() -> Result<usize> {
Error::demux(unsafe { redox_get_rgid_v1() })
}
#[inline]
pub fn getpid() -> Result<usize> {
Error::demux(unsafe { redox_get_pid_v1() })
}
#[inline]
pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
Error::demux(unsafe { redox_setrens_v1(rns, ens) })
}
#[inline]
pub fn waitpid(pid: usize, status: &mut i32, options: i32) -> Result<usize> {
Error::demux(unsafe { redox_waitpid_v1(pid, status as *mut i32, options as u32) })
}
#[inline]
pub fn kill(pid: usize, signal: u32) -> Result<()> {
Error::demux(unsafe { redox_kill_v1(pid, signal) }).map(|_| ())
}
#[inline]
pub fn clock_gettime(clock: i32) -> Result<data::TimeSpec> {
unsafe {
let mut ret = MaybeUninit::uninit();
Error::demux(redox_clock_gettime_v1(clock as usize, ret.as_mut_ptr()))?;
Ok(ret.assume_init())
}
}
#[inline]
pub fn sigprocmask(
how: i32,
newmask: Option<&data::SigSet>,
oldmask: Option<&mut data::SigSet>,
) -> Result<()> {
Error::demux(unsafe {
redox_sigprocmask_v1(
how as u32,
newmask.map_or(core::ptr::null(), |m| m),
oldmask.map_or(core::ptr::null_mut(), |m| m),
)
})
.map(|_| ())
}
#[inline]
pub fn sigaction(
signal: i32,
newact: Option<&data::SigAction>,
oldact: Option<&mut data::SigAction>,
) -> Result<()> {
Error::demux(unsafe {
redox_sigaction_v1(
signal as u32,
newact.map_or(core::ptr::null(), |m| m),
oldact.map_or(core::ptr::null_mut(), |m| m),
)
})
.map(|_| ())
}
#[derive(Clone, Copy, Debug)]
pub struct MmapArgs {
pub addr: *mut (),
pub length: usize,
pub prot: u32,
pub flags: u32,
pub fd: usize,
pub offset: u64,
}
#[inline]
pub unsafe fn mmap(args: MmapArgs) -> Result<*mut ()> {
Error::demux(redox_mmap_v1(
args.addr,
args.length,
args.prot,
args.flags,
args.fd,
args.offset,
))
.map(|addr| addr as *mut ())
}
#[inline]
pub unsafe fn munmap(addr: *mut (), length: usize) -> Result<()> {
Error::demux(redox_munmap_v1(addr, length)).map(|_| ())
}
}