feat: Move redox-rt::protocol into libredox::protocol. Add getdents and futimens.

This commit is contained in:
Ibuki Omatsu
2026-02-27 15:37:26 +00:00
committed by Jeremy Soller
parent 6a75c953a6
commit 17f21113a0
2 changed files with 364 additions and 31 deletions
+9 -6
View File
@@ -1,7 +1,7 @@
[package]
name = "libredox"
authors = ["4lDO2 <4lDO2@protonmail.com>"]
version = "0.1.12"
version = "0.1.13"
edition = "2021"
license = "MIT"
description = "Redox stable ABI"
@@ -11,13 +11,16 @@ exclude = ["target"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["call", "std", "redox_syscall"]
call = []
std = []
default = ["base", "call", "std", "redox_syscall", "protocol"]
base = []
call = ["base", "libc"]
std = ["base", "libc"]
protocol = ["plain", "bitflags", "redox_syscall"]
mkns = ["ioslice"]
[dependencies]
bitflags = "2"
libc = "0.2"
bitflags = { version = "2", optional = true }
libc = { version = "0.2", optional = true }
redox_syscall = { version = "0.7", optional = true }
ioslice = { version = "0.6", optional = true }
plain = { version = "0.2", optional = true }
+355 -25
View File
@@ -4,6 +4,7 @@
#[cfg(feature = "call")]
use self::error::{Error, Result};
#[cfg(feature = "base")]
pub mod error {
use super::*;
@@ -107,6 +108,7 @@ pub mod 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,
@@ -166,6 +168,7 @@ pub mod flag {
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,
@@ -184,6 +187,7 @@ pub mod errno {
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;
@@ -238,14 +242,19 @@ extern "C" {
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_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;
/* TODO: Support unlinkat using std_fs_call
fn redox_unlinkat_v0(fd: usize, buf: *const u8, path_len: usize, flags: u32) -> RawResult;
*/
fn redox_fpath_v1(fd: usize, dst_base: *mut u8, dst_len: usize) -> RawResult;
fn redox_close_v1(fd: usize) -> RawResult;
// NOTE: While the Redox kernel currently doesn't distinguish between threads and processes,
@@ -323,6 +332,7 @@ impl Fd {
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)?))
}
@@ -356,8 +366,22 @@ impl Fd {
call::write(self.raw(), buf)
}
#[inline]
pub fn fpath(&self, path: &mut [u8]) -> Result<usize> {
call::fpath(self.raw(), path)
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<()> {
@@ -367,22 +391,24 @@ impl Fd {
pub fn fdatasync(&self) -> Result<()> {
call::fdatasync(self.raw())
}
#[inline]
pub fn chmod(&self, new_mode: u16) -> Result<()> {
call::fchmod(self.raw(), new_mode)
pub fn ftruncate(self, len: usize) -> Result<()> {
call::ftruncate(self.raw(), len)
}
#[inline]
pub fn chown(&self, new_uid: u32, new_gid: u32) -> Result<()> {
call::fchown(self.raw(), new_uid, new_gid)
pub fn futimens(self, times: &[data::TimeSpec; 2]) -> Result<()> {
call::futimens(self.raw(), times)
}
pub fn stat(&self) -> Result<data::Stat> {
call::fstat(self.raw())
/* TODO: Support unlinkat using std_fs_call
#[inline]
pub fn unlinkat(&self, path: &str, flags: i32) -> Result<()> {
call::unlinkat(self.raw(), path, flags)
}
pub fn statvfs(&self) -> Result<data::StatVfs> {
call::fstatvfs(self.raw())
*/
#[inline]
pub fn fpath(&self, path: &mut [u8]) -> Result<usize> {
call::fpath(self.raw(), path)
}
// TODO: futimens
#[inline]
pub fn close(self) -> Result<()> {
call::close(self.into_raw())
@@ -477,14 +503,6 @@ pub mod call {
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(())
@@ -495,8 +513,8 @@ pub mod call {
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()) })
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> {
@@ -515,10 +533,34 @@ pub mod call {
}
}
#[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(())
}
/* TODO: Support unlinkat using std_fs_call
#[inline]
pub fn unlinkat(fd: usize, path: impl AsRef<[u8]>, flags: i32) -> Result<()> {
let path = path.as_ref();
Error::demux(unsafe { redox_unlinkat_v0(fd, path.as_ptr(), path.len(), flags as u32) })
.map(|_| ())
}
*/
#[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) })?;
@@ -741,3 +783,291 @@ pub mod call {
.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,
// TODO: replace with sendfd equivalent syscall for sending memory
SyncSigPctl = 10,
Sigdeq = 11,
Getppid = 12,
Rename = 13,
DisableSetpgid = 14,
// Temporary calls for getting process credentials
GetProcCredentials = 15,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(usize)]
pub enum ThreadCall {
// TODO: replace with sendfd equivalent syscall for sending memory, or force userspace to
// obtain its TCB memory from this server
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,
_ => 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;
}
}
/// True if status indicates the child is stopped.
pub fn wifstopped(status: usize) -> bool {
(status & 0xff) == 0x7f
}
/// If wifstopped(status), the signal that stopped the child.
pub fn wstopsig(status: usize) -> usize {
(status >> 8) & 0xff
}
/// True if status indicates the child continued after a stop.
pub fn wifcontinued(status: usize) -> bool {
status == 0xffff
}
/// True if STATUS indicates termination by a signal.
pub fn wifsignaled(status: usize) -> bool {
((status & 0x7f) + 1) as i8 >= 2
}
/// If wifsignaled(status), the terminating signal.
pub fn wtermsig(status: usize) -> usize {
status & 0x7f
}
/// True if status indicates normal termination.
pub fn wifexited(status: usize) -> bool {
wtermsig(status) == 0
}
/// If wifexited(status), the exit status.
pub fn wexitstatus(status: usize) -> usize {
(status >> 8) & 0xff
}
/// True if status indicates a core dump was created.
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, // TODO: usize?
}
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 {
/// List schemes in the namespace
const LIST = 1 << 0;
/// Register a new scheme in the namespace
const INSERT = 1 << 1;
/// Delete a scheme from the namespace
const DELETE = 1 << 2;
/// Get scheme creation capabilities of the namespace
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,
})
}
}
}