#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "call")]
use self::error::{Error, Result};
#[cfg(feature = "base")]
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)
}
}
#[cfg(feature = "call")]
pub fn description(self, buf: &mut [u8]) -> &str {
call::strerror(self.errno, buf).map_or("unknown error", |(desc, _)| desc)
}
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "call")]
{
write!(f, "{}", self.description(&mut [0; 256]))
}
#[cfg(not(feature = "call"))]
{
write!(f, "Error {} (strerror unavailable)", self.errno)
}
}
}
impl core::fmt::Debug for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "call")]
{
write!(
f,
"Error `{}` {}",
self.description(&mut [0; 256]),
self.errno
)
}
#[cfg(not(feature = "call"))]
{
write!(f, "Error {} (strerror unavailable)", self.errno)
}
}
}
#[cfg(feature = "redox_syscall")]
impl From<syscall::Error> for Error {
fn from(value: syscall::Error) -> Self {
Self {
errno: value.errno.try_into().unwrap_or(u16::MAX),
}
}
}
#[cfg(feature = "redox_syscall")]
impl From<Error> for syscall::Error {
fn from(value: Error) -> Self {
Self::new(value.errno())
}
}
#[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>;
}
#[cfg(feature = "base")]
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::{MSG_DONTROUTE, MSG_OOB, MSG_PEEK, MSG_DONTWAIT, MSG_EOR, };
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 const WNOHANG: u32 = libc::WNOHANG as u32;
pub const WUNTRACED: u32 = libc::WUNTRACED as u32;
pub const WCONTINUED: u32 = libc::WCONTINUED as u32;
}
#[cfg(feature = "base")]
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,
};
}
#[cfg(feature = "base")]
pub mod data {
pub use libc::iovec as IoVec;
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;
}
#[cfg(feature = "call")]
type RawResult = usize;
#[cfg(feature = "call")]
#[allow(dead_code)]
extern "C" {
fn redox_open_v1(path_base: *const u8, path_len: usize, flags: u32, mode: u16) -> RawResult;
fn redox_openat_v1(
fd: usize,
buf: *const u8,
path_len: usize,
flags: u32,
fcntl_flags: u32,
) -> 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_fchmod_v1(fd: usize, new_mode: u16) -> RawResult;
fn redox_fchown_v1(fd: usize, new_uid: u32, new_gid: u32) -> RawResult;
fn redox_getdents_v0(fd: usize, buf: *mut u8, buf_len: usize, opaque: u64) -> 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_fsync_v1(fd: usize) -> RawResult;
fn redox_fdatasync_v1(fd: usize) -> RawResult;
fn redox_ftruncate_v0(fd: usize, len: usize) -> RawResult;
fn redox_futimens_v1(fd: usize, times: *const data::TimeSpec) -> RawResult;
fn redox_fpath_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> 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_get_ens_v0() -> RawResult;
fn redox_get_ns_v0() -> RawResult;
fn redox_get_proc_credentials_v1(cap_fd: usize, target_pid: usize, buf: &mut [u8])
-> RawResult;
fn redox_setrens_v1(rns: usize, ens: usize) -> RawResult;
fn redox_mkns_v1(names: *const data::IoVec, num_names: usize, _flags: u32) -> 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;
fn redox_strerror_v1(dst: *mut u8, dst_len: *mut usize, error: u32) -> RawResult;
fn redox_sys_call_v0(
fd: usize,
payload: *mut u8,
payload_len: usize,
flags: usize,
metadata: *const u64,
metadata_len: usize,
) -> RawResult;
fn redox_get_socket_token_v0(fd: usize, payload: *mut u8, payload_len: usize) -> RawResult;
fn redox_setns_v0(fd: usize) -> RawResult;
fn redox_register_scheme_to_ns_v0(
ns_fd: usize,
name_base: *const u8,
name_len: usize,
cap_fd: usize,
) -> RawResult;
}
#[cfg(feature = "call")]
pub struct Fd(usize);
#[cfg(feature = "call")]
impl Fd {
pub fn new(raw: usize) -> Self {
Self(raw)
}
#[inline]
pub fn open(path: &str, flags: i32, mode: u16) -> Result<Self> {
Ok(Self(call::open(path, flags, mode)?))
}
#[inline]
pub fn openat(&self, path: &str, flags: i32, fcntl_flags: u32) -> Result<Self> {
Ok(Self(call::openat(self.raw(), path, flags, fcntl_flags)?))
}
#[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 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)
}
#[inline]
pub fn getdents(self, buf: &mut [u8], opaque: u64) -> Result<usize> {
call::getdents(self.raw(), buf, opaque)
}
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 fsync(&self) -> Result<()> {
call::fsync(self.raw())
}
#[inline]
pub fn fdatasync(&self) -> Result<()> {
call::fdatasync(self.raw())
}
#[inline]
pub fn ftruncate(self, len: usize) -> Result<()> {
call::ftruncate(self.raw(), len)
}
#[inline]
pub fn futimens(self, times: &[data::TimeSpec; 2]) -> Result<()> {
call::futimens(self.raw(), times)
}
#[inline]
pub fn fpath(&self, path: &mut [u8]) -> Result<usize> {
call::fpath(self.raw(), path)
}
#[inline]
pub fn close(self) -> Result<()> {
call::close(self.into_raw())
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_ro(
&self,
payload: &mut [u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
call::call_ro(self.raw(), payload, flags, metadata)
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_wo(
&self,
payload: &[u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
call::call_wo(self.raw(), payload, flags, metadata)
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_rw(
&self,
payload: &mut [u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
call::call_rw(self.raw(), payload, flags, metadata)
}
}
#[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 openat(
fd: usize,
path: impl AsRef<[u8]>,
flags: i32,
fcntl_flags: u32,
) -> Result<usize> {
let path = path.as_ref();
Ok(Error::demux(unsafe {
redox_openat_v1(fd, path.as_ptr(), path.len(), flags as u32, fcntl_flags)
})?)
}
#[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 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 getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
Error::demux(unsafe { redox_getdents_v0(fd, buf.as_mut_ptr(), buf.len(), opaque) })
}
#[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 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 ftruncate(raw_fd: usize, new_size: usize) -> Result<()> {
Error::demux(unsafe { redox_ftruncate_v0(raw_fd, new_size) }).map(|_| ())
}
#[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 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 close(raw_fd: usize) -> Result<()> {
Error::demux(unsafe { redox_close_v1(raw_fd) })?;
Ok(())
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_ro(
fd: usize,
payload: &mut [u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
redox_sys_call_v0(
fd,
payload.as_mut_ptr(),
payload.len(),
(flags | syscall::CallFlags::READ).bits(),
metadata.as_ptr(),
metadata.len(),
)
})?)
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_wo(
fd: usize,
payload: &[u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
redox_sys_call_v0(
fd,
payload.as_ptr() as *mut u8,
payload.len(),
(flags | syscall::CallFlags::WRITE).bits(),
metadata.as_ptr(),
metadata.len(),
)
})?)
}
#[cfg(feature = "redox_syscall")]
#[inline]
pub fn call_rw(
fd: usize,
payload: &mut [u8],
flags: syscall::CallFlags,
metadata: &[u64],
) -> Result<usize> {
Ok(Error::demux(unsafe {
redox_sys_call_v0(
fd,
payload.as_mut_ptr(),
payload.len(),
(flags | syscall::CallFlags::READ | syscall::CallFlags::WRITE).bits(),
metadata.as_ptr(),
metadata.len(),
)
})?)
}
#[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 getens() -> Result<usize> {
Error::demux(unsafe { redox_get_ens_v0() })
}
#[inline]
pub fn get_proc_credentials(cap_fd: usize, target_pid: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_get_proc_credentials_v1(cap_fd, target_pid, buf) })
}
#[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(|_| ())
}
#[inline]
pub fn strerror(error: u16, desc: &mut [u8]) -> Option<(&str, usize)> {
unsafe {
let mut len_inout = desc.len();
let copied_len = Error::demux(redox_strerror_v1(
desc.as_mut_ptr(),
&mut len_inout,
error.into(),
))
.ok()?;
Some((
core::str::from_utf8_unchecked(&desc[..copied_len]),
len_inout,
))
}
}
#[inline]
#[cfg(feature = "mkns")]
pub fn mkns(names: &[ioslice::IoSlice]) -> Result<usize> {
let iovecs = ioslice::IoSlice::cast_to_raw_iovecs(names);
unsafe { Error::demux(redox_mkns_v1(iovecs.as_ptr(), iovecs.len(), 0)) }
}
#[inline]
pub fn get_socket_token(fd: usize, buf: &mut [u8]) -> Result<usize> {
Error::demux(unsafe { redox_get_socket_token_v0(fd, buf.as_mut_ptr(), buf.len()) })
}
#[inline]
pub fn setns(fd: usize) -> Result<usize> {
Error::demux(unsafe { redox_setns_v0(fd) })
}
#[inline]
pub fn getns() -> Result<usize> {
Error::demux(unsafe { redox_get_ns_v0() })
}
#[inline]
pub fn register_scheme_to_ns(ns_fd: usize, name: impl AsRef<str>, cap_fd: usize) -> Result<()> {
let name = name.as_ref();
Error::demux(unsafe {
redox_register_scheme_to_ns_v0(ns_fd, name.as_ptr(), name.len(), cap_fd)
})
.map(|_| ())
}
}
#[cfg(feature = "protocol")]
pub mod protocol {
use bitflags::bitflags;
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct ProcMeta {
pub pid: u32,
pub pgid: u32,
pub ppid: u32,
pub ruid: u32,
pub euid: u32,
pub suid: u32,
pub rgid: u32,
pub egid: u32,
pub sgid: u32,
pub ens: u32,
pub rns: u32,
}
unsafe impl plain::Plain for ProcMeta {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
pub enum ProcCall {
Waitpid = 0,
Setrens = 1,
Exit = 2,
Waitpgid = 3,
SetResugid = 4,
Setpgid = 5,
Getsid = 6,
Setsid = 7,
Kill = 8,
Sigq = 9,
SyncSigPctl = 10,
Sigdeq = 11,
Getppid = 12,
Rename = 13,
DisableSetpgid = 14,
GetProcCredentials = 15,
SetProcPriority = 16,
GetProcPriority = 17,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
pub enum ThreadCall {
SyncSigTctl = 0,
SignalThread = 1,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
#[non_exhaustive]
pub enum SocketCall {
Bind = 0,
Connect = 1,
SetSockOpt = 2,
GetSockOpt = 3,
SendMsg = 4,
RecvMsg = 5,
Unbind = 6,
GetToken = 7,
GetPeerName = 8,
Shutdown = 9,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
#[non_exhaustive]
pub enum FsCall {
Connect = 0,
}
impl ProcCall {
pub fn try_from_raw(raw: usize) -> Option<Self> {
Some(match raw {
0 => Self::Waitpid,
1 => Self::Setrens,
2 => Self::Exit,
3 => Self::Waitpgid,
4 => Self::SetResugid,
5 => Self::Setpgid,
6 => Self::Getsid,
7 => Self::Setsid,
8 => Self::Kill,
9 => Self::Sigq,
10 => Self::SyncSigPctl,
11 => Self::Sigdeq,
12 => Self::Getppid,
13 => Self::Rename,
14 => Self::DisableSetpgid,
15 => Self::GetProcCredentials,
16 => Self::SetProcPriority,
17 => Self::GetProcPriority,
_ => return None,
})
}
}
impl ThreadCall {
pub fn try_from_raw(raw: usize) -> Option<Self> {
Some(match raw {
0 => Self::SyncSigTctl,
1 => Self::SignalThread,
_ => return None,
})
}
}
impl SocketCall {
pub fn try_from_raw(raw: usize) -> Option<Self> {
Some(match raw {
0 => Self::Bind,
1 => Self::Connect,
2 => Self::SetSockOpt,
3 => Self::GetSockOpt,
4 => Self::SendMsg,
5 => Self::RecvMsg,
6 => Self::Unbind,
7 => Self::GetToken,
8 => Self::GetPeerName,
9 => Self::Shutdown,
_ => return None,
})
}
}
impl FsCall {
pub fn try_from_raw(raw: usize) -> Option<Self> {
Some(match raw {
0 => Self::Connect,
_ => return None,
})
}
}
bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct WaitFlags: usize {
const WNOHANG = 0x01;
const WUNTRACED = 0x02;
const WCONTINUED = 0x08;
}
}
pub fn wifstopped(status: usize) -> bool {
(status & 0xff) == 0x7f
}
pub fn wstopsig(status: usize) -> usize {
(status >> 8) & 0xff
}
pub fn wifcontinued(status: usize) -> bool {
status == 0xffff
}
pub fn wifsignaled(status: usize) -> bool {
((status & 0x7f) + 1) as i8 >= 2
}
pub fn wtermsig(status: usize) -> usize {
status & 0x7f
}
pub fn wifexited(status: usize) -> bool {
wtermsig(status) == 0
}
pub fn wexitstatus(status: usize) -> usize {
(status >> 8) & 0xff
}
pub fn wcoredump(status: usize) -> bool {
(status & 0x80) != 0
}
#[derive(Clone, Copy, Debug)]
pub enum ProcKillTarget {
ThisGroup,
SingleProc(usize),
ProcGroup(usize),
All,
}
impl ProcKillTarget {
pub fn raw(self) -> usize {
match self {
Self::ThisGroup => 0,
Self::SingleProc(p) => p,
Self::ProcGroup(g) => usize::wrapping_neg(g),
Self::All => usize::wrapping_neg(1),
}
}
pub fn from_raw(raw: usize) -> Self {
let raw = raw as isize;
if raw == 0 {
Self::ThisGroup
} else if raw == -1 {
Self::All
} else if raw < 0 {
Self::ProcGroup(raw.wrapping_neg() as usize)
} else {
Self::SingleProc(raw as usize)
}
}
}
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[repr(C)]
pub struct RtSigInfo {
pub arg: usize,
pub code: i32,
pub uid: u32,
pub pid: u32, }
unsafe impl plain::Plain for RtSigInfo {}
pub const SIGHUP: usize = 1;
pub const SIGINT: usize = 2;
pub const SIGQUIT: usize = 3;
pub const SIGILL: usize = 4;
pub const SIGTRAP: usize = 5;
pub const SIGABRT: usize = 6;
pub const SIGBUS: usize = 7;
pub const SIGFPE: usize = 8;
pub const SIGKILL: usize = 9;
pub const SIGUSR1: usize = 10;
pub const SIGSEGV: usize = 11;
pub const SIGUSR2: usize = 12;
pub const SIGPIPE: usize = 13;
pub const SIGALRM: usize = 14;
pub const SIGTERM: usize = 15;
pub const SIGSTKFLT: usize = 16;
pub const SIGCHLD: usize = syscall::SIGCHLD;
pub const SIGCONT: usize = 18;
pub const SIGSTOP: usize = 19;
pub const SIGTSTP: usize = syscall::SIGTSTP;
pub const SIGTTIN: usize = syscall::SIGTTIN;
pub const SIGTTOU: usize = syscall::SIGTTOU;
pub const SIGURG: usize = 23;
pub const SIGXCPU: usize = 24;
pub const SIGXFSZ: usize = 25;
pub const SIGVTALRM: usize = 26;
pub const SIGPROF: usize = 27;
pub const SIGWINCH: usize = 28;
pub const SIGIO: usize = 29;
pub const SIGPWR: usize = 30;
pub const SIGSYS: usize = 31;
bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, Ord, Hash, PartialEq, PartialOrd)]
pub struct NsPermissions: usize {
const LIST = 1 << 0;
const INSERT = 1 << 1;
const DELETE = 1 << 2;
const SCHEME_CREATE = 1 << 3;
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
pub enum NsDup {
ForkNs = 0,
ShrinkPermissions = 1,
IssueRegister = 2,
}
impl NsDup {
pub fn try_from_raw(raw: usize) -> Option<Self> {
Some(match raw {
0 => Self::ForkNs,
1 => Self::ShrinkPermissions,
2 => Self::IssueRegister,
_ => return None,
})
}
}
}