libc: better errno, better pidfd

This commit is contained in:
Mark Poliakov 2024-11-29 19:40:17 +02:00
parent 6017e1044a
commit cd22da9098
49 changed files with 475 additions and 397 deletions

View File

@ -297,7 +297,7 @@ impl<'a, A: BlockAllocator> BVec<'a, A> {
let l2 = &self.l2[l2_outer];
debug_assert!(!l2.is_null());
return &l2[l2_inner];
&l2[l2_inner]
} else {
panic!("Block index too large");
}
@ -325,7 +325,7 @@ impl<'a, A: BlockAllocator> BVec<'a, A> {
let l2 = &mut self.l2[l2_outer];
debug_assert!(!l2.is_null());
return &mut l2[l2_inner];
&mut l2[l2_inner]
} else {
panic!("Block index too large");
}

View File

@ -68,7 +68,7 @@ pub struct MemoryFilesystem<A: BlockAllocator> {
impl<A: BlockAllocator> MemoryFilesystem<A> {
fn make_path(
self: &Rc<Self>,
// self: &Rc<Self>,
at: &NodeRef,
path: &Path,
create: bool,
@ -106,7 +106,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
Ok(node)
} else {
assert!(node.is_directory());
self.make_path(&node, rest, create)
Self::make_path(&node, rest, create)
}
}
@ -144,7 +144,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
log::debug!("Make path {:?}", path);
let (dirname, filename) = path.split_right();
let parent = self.make_path(&root, dirname, true)?;
let parent = Self::make_path(&root, dirname, true)?;
let node = self.create_node_initial(hdr)?;
parent.add_child(filename, node)?;
@ -157,7 +157,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
};
let path = Path::from_str(hdr.name.as_str()?.trim_matches('/'));
let node = self.make_path(&root, path, false)?;
let node = Self::make_path(&root, path, false)?;
assert_eq!(node.ty(), hdr.node_kind());
let uid = unsafe { UserId::from_raw(usize::from(&hdr.uid) as u32) };

View File

@ -129,34 +129,36 @@ impl BoolEvent {
Ok(())
}
pub fn poll_reset(&self, cx: &mut Context<'_>) -> Poll<()> {
self.notify.register(cx.waker());
if self
.state
.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
// Event set and immediately reset
self.notify.remove(cx.waker());
Poll::Ready(())
} else {
Poll::Pending
}
}
pub fn poll(&self, cx: &mut Context<'_>) -> Poll<()> {
self.notify.register(cx.waker());
if self.is_signalled() {
self.notify.remove(cx.waker());
Poll::Ready(())
} else {
Poll::Pending
}
}
pub async fn wait_reset(&self) {
poll_fn(|cx| {
self.notify.register(cx.waker());
if self
.state
.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed)
.is_ok()
{
// Event set and immediately reset
self.notify.remove(cx.waker());
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
poll_fn(|cx| self.poll_reset(cx)).await
}
pub async fn wait(&self) {
poll_fn(|cx| {
self.notify.register(cx.waker());
if self.is_signalled() {
self.notify.remove(cx.waker());
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
poll_fn(|cx| self.poll(cx)).await
}
}

View File

@ -294,6 +294,10 @@ impl Process {
self.map_image(|image| image.load_base)
}
pub fn strong_child(&self, id: ProcessId) -> Option<Arc<Self>> {
self.inner.read().strong_child(id)
}
pub fn as_single_thread(&self) -> Option<Arc<Thread>> {
let inner = self.inner.read();
if inner.threads.len() != 1 {

View File

@ -20,6 +20,7 @@ use yggdrasil_abi::{
DeviceRequest, DirectoryEntry, OpenOptions, PipeOptions, RawFd, SeekFrom, TerminalOptions,
TerminalSize, TimerOptions,
},
process::{ProcessWait, WaitFlags},
};
use crate::{
@ -165,8 +166,14 @@ impl File {
}
/// Creates a new [PidFile]-backed file
pub fn new_pid(process: &Arc<Process>) -> FileRef {
Arc::new(Self::Pid(PidFile::new(process)))
pub fn new_pid(
parent: Arc<Process>,
wait: &ProcessWait,
flags: WaitFlags,
) -> Result<FileRef, Error> {
PidFile::new(parent, wait, flags)
.map(Self::Pid)
.map(Arc::new)
}
/// Constructs a [File] from a [PacketSocket], [ConnectionSocket] or a [ListenerSocket].

View File

@ -1,58 +1,129 @@
use alloc::sync::{Arc, Weak};
use alloc::sync::Arc;
use core::{
fmt,
task::{Context, Poll},
};
use libk_util::io::Read;
use yggdrasil_abi::{error::Error, process::ExitCode};
use yggdrasil_abi::{
error::Error,
process::{ExitCode, ProcessId, ProcessWait, WaitFlags},
};
use crate::task::process::Process;
use super::FileReadiness;
#[derive(Clone)]
pub struct PidFile {
process: Weak<Process>,
pub struct PidFileProcess {
parent: Arc<Process>,
child: Arc<Process>,
non_blocking: bool,
}
#[allow(unused)]
#[derive(Clone)]
pub struct PidFileAnyChild {
parent: Arc<Process>,
non_blocking: bool,
}
#[derive(Clone)]
pub enum PidFile {
Process(PidFileProcess),
AnyChild(PidFileAnyChild),
}
impl PidFileProcess {
pub fn new(parent: Arc<Process>, child: ProcessId, flags: WaitFlags) -> Result<Self, Error> {
let child = parent.strong_child(child).ok_or(Error::ProcessNotFound)?;
Ok(Self {
parent,
child,
non_blocking: flags.contains(WaitFlags::NON_BLOCKING),
})
}
pub fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if let Some(status) = self.status() {
return Ok(PidFile::write_completion(buf, self.child.id, status));
}
if self.non_blocking {
return Err(Error::WouldBlock);
}
block! {
loop {
if let Some(status) = self.status() {
break PidFile::write_completion(buf, self.child.id, status);
}
self.parent.child_exit_notify.wait_reset().await;
}
}
}
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
self.parent.child_exit_notify.poll_reset(cx).map(Ok)
}
fn status(&self) -> Option<ExitCode> {
self.child.get_exit_status()
}
}
impl PidFile {
pub fn new(process: &Arc<Process>) -> Self {
Self {
process: Arc::downgrade(process),
pub fn new(parent: Arc<Process>, wait: &ProcessWait, flags: WaitFlags) -> Result<Self, Error> {
match wait {
&ProcessWait::Process(id) => PidFileProcess::new(parent, id, flags).map(Self::Process),
&ProcessWait::Group(_id) => todo!(),
ProcessWait::AnyChild => todo!(),
}
}
fn write_completion(buf: &mut [u8], pid: ProcessId, status: ExitCode) -> usize {
debug_assert!(buf.len() >= size_of::<u32>() + size_of::<i32>());
buf[..size_of::<u32>()].copy_from_slice(&pid.bits().to_ne_bytes());
match status {
ExitCode::Exited(code) => buf[size_of::<u32>()..size_of::<u32>() + size_of::<i32>()]
.copy_from_slice(&code.to_ne_bytes()),
_ => todo!(),
}
size_of::<u32>() + size_of::<i32>()
}
}
impl Read for PidFile {
fn read(&self, buf: &mut [u8]) -> Result<usize, Error> {
if buf.len() < size_of::<i32>() {
if buf.len() < size_of::<u32>() + size_of::<i32>() {
return Err(Error::BufferTooSmall);
}
let process = self.process.upgrade().ok_or(Error::DoesNotExist)?;
let exit = block!(process.wait_for_exit().await)?;
match exit {
ExitCode::Exited(code) => buf[..size_of::<i32>()].copy_from_slice(&code.to_le_bytes()),
_ => todo!(),
match self {
Self::Process(pid) => pid.read(buf),
Self::AnyChild(_) => todo!(),
}
Ok(size_of::<i32>())
}
}
impl FileReadiness for PidFile {
fn poll_read(&self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
match self.process.upgrade() {
Some(process) => process.poll_read(cx),
None => Poll::Ready(Err(Error::DoesNotExist)),
match self {
Self::Process(pid) => pid.poll_read(cx),
Self::AnyChild(_) => todo!(),
}
}
}
impl fmt::Debug for PidFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.process.upgrade() {
Some(process) => f.debug_struct("PidFile").field("pid", &process.id).finish(),
None => f.debug_struct("PidFile").field("pid", &"<none>").finish(),
}
let mut s = f.debug_struct("PidFile");
match self {
Self::Process(pid) => s
.field("child", &pid.child.id)
.field("non_blocking", &pid.non_blocking),
Self::AnyChild(pid) => s.field("non_blocking", &pid.non_blocking),
};
s.finish()
}
}

View File

@ -7,12 +7,12 @@ use abi::{
MessageDestination, OpenOptions, PipeOptions, PollControl, RawFd, ReceivedMessageMetadata,
SeekFrom, SentMessage, TerminalOptions, TerminalSize, TimerOptions,
},
process::ProcessId,
process::{ProcessWait, WaitFlags},
};
use alloc::boxed::Box;
use libk::{
block,
task::{process::Process, thread::Thread},
task::thread::Thread,
vfs::{self, File, MessagePayload, Read, Seek, Write},
};
@ -243,13 +243,12 @@ pub(crate) fn create_timer(options: TimerOptions) -> Result<RawFd, Error> {
})
}
pub(crate) fn create_pid(pid: ProcessId) -> Result<RawFd, Error> {
pub(crate) fn create_pid(wait: &ProcessWait, flags: WaitFlags) -> Result<RawFd, Error> {
let thread = Thread::current();
let process = thread.process();
run_with_io(&process, |mut io| {
let process = Process::get(pid).ok_or(Error::DoesNotExist)?;
let file = File::new_pid(&process);
let file = File::new_pid(process.clone(), wait, flags)?;
let fd = io.files.place_file(file, true)?;
Ok(fd)
})

View File

@ -321,9 +321,7 @@ pub(crate) fn wait_thread(id: u32) -> Result<(), Error> {
let this_thread = Thread::current();
let process = this_thread.process();
let result = block!(process.wait_for_thread(tid).await)?;
result
block!(process.wait_for_thread(tid).await)?
}
pub(crate) fn get_thread_option(option: &mut ThreadOption) -> Result<(), Error> {

View File

@ -28,4 +28,5 @@ enum Error(u32) {
UndefinedSyscall = 25,
DirectoryNotEmpty = 26,
NotConnected = 27,
ProcessNotFound = 28,
}

View File

@ -122,7 +122,7 @@ syscall device_request(fd: RawFd, req: &mut DeviceRequest) -> Result<()>;
// Misc I/O
syscall open_channel(name: &str, subscribe: bool) -> Result<RawFd>;
syscall create_timer(options: TimerOptions) -> Result<RawFd>;
syscall create_pid(pid: ProcessId) -> Result<RawFd>;
syscall create_pid(target: &ProcessWait, flags: WaitFlags) -> Result<RawFd>;
syscall create_pty(opts: &TerminalOptions, size: &TerminalSize, fds: &mut [MaybeUninit<RawFd>; 2]) -> Result<()>;
syscall create_shared_memory(size: usize) -> Result<RawFd>;
syscall create_poll_channel() -> Result<RawFd>;

View File

@ -9,15 +9,17 @@
)]
#![no_std]
#![deny(missing_docs)]
#![allow(nonstandard_style)]
#![allow(unused)]
#![allow(nonstandard_style, clippy::new_without_default)]
// #[cfg(not(feature = "rustc-dep-of-std"))]
#[allow(unused_extern_crates)]
extern crate compiler_builtins;
extern crate yggdrasil_abi as abi;
#[allow(unused_extern_crates)]
extern crate alloc;
extern crate yggdrasil_abi as abi;
pub use abi::error::Error;
pub use abi::path;
pub mod debug;

View File

@ -7,6 +7,7 @@ use abi::{error::Error, io::RawFd};
use crate::sys;
#[allow(unused_macros)]
macro socket_option_variant {
($opt:ident: bool) => { $crate::net::SocketOption::$opt(false) },
($opt:ident: Option) => { $crate::net::SocketOption::$opt(None) },

View File

@ -6,7 +6,6 @@ use abi::{
mem::{MappingFlags, MappingSource},
process::{ExitCode, ProcessOption, Signal, SignalEntryData, ThreadOption},
};
use alloc::boxed::Box;
/// Describes how a signal should be handled
#[derive(Debug, Clone, Copy)]
@ -25,6 +24,8 @@ pub enum SignalHandler {
const MAX_SIGNALS: usize = 16;
static mut TABLE: [SignalHandler; MAX_SIGNALS] = [const { SignalHandler::Terminate }; MAX_SIGNALS];
// TODO remove unused for i686
#[allow(unused)]
unsafe extern "C" fn common_signal_entry(data: &SignalEntryData) -> ! {
let index = data.signal.into_raw() as usize;
@ -160,6 +161,7 @@ pub fn setup_signal_full(size: usize) -> Result<(), Error> {
// implementation details
// TODO
#[cfg(any(target_arch = "x86", rust_analyzer))]
mod imp {
// i686 is a bit tricky: cdecl ABI requires the arguments to be passed on the stack, while

View File

@ -2,7 +2,7 @@
use core::{
ptr,
sync::atomic::{AtomicU32, AtomicUsize, Ordering},
sync::atomic::{AtomicU32, Ordering},
};
use abi::{
@ -27,6 +27,7 @@ pub struct Thread<R> {
/// Describes a "handle" to some runtime thread. This is what gets returned to the caller
/// when a thread is spawned and can be used to, e.g., join the created thread later.
pub struct ThreadHandle<R> {
#[allow(unused)]
stack: Option<OwnedStack>,
thread: Arc<Thread<R>>,
}
@ -157,7 +158,7 @@ impl<R> Thread<R> {
let mut argument = unsafe { Box::from_raw(raw) };
// Setup TLS as soon as possible
if let Err(err) = unsafe { thread_local::init_tls(argument.tls_image, true) } {
if let Err(err) = thread_local::init_tls(argument.tls_image, true) {
crate::debug_trace!("thread_entry failed: TLS init error: {err:?}");
// TODO result is uninit
unsafe { crate::sys::exit_thread() };
@ -196,7 +197,7 @@ impl<R> Thread<R> {
None => unreachable!(),
};
argument.thread_self.result.write().insert(result);
argument.thread_self.result.write().replace(result);
}
unsafe { crate::sys::exit_thread() };
@ -224,7 +225,7 @@ impl<R> ThreadHandle<R> {
pub fn join_uninterruptible(self) -> Option<R> {
loop {
match unsafe { crate::sys::wait_thread(self.thread.id.load(Ordering::Acquire)) } {
Ok(result) => (),
Ok(_) => (),
Err(Error::Interrupted) => continue,
Err(error) => panic!("wait_thread syscall returned error: {error:?}"),
}

View File

@ -8,7 +8,7 @@ use alloc::{boxed::Box, vec::Vec};
use abi::{
error::Error,
process::{auxv, AuxValue, ThreadOption},
process::{auxv, AuxValue},
};
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
@ -56,11 +56,10 @@ pub struct Dtv {
entries: Vec<*mut c_void>,
// Entries for pthread_setspecific()-like behavior
specific: Vec<*mut c_void>,
// Self-reference for the thread
thread_self: *mut c_void,
}
struct TcbHeader {
#[allow(unused)]
self_pointer: usize,
dtv_pointer: *mut Dtv,
}
@ -128,7 +127,6 @@ impl Dtv {
Self {
entries: Vec::new(),
specific: Vec::new(),
thread_self: null_mut(),
}
}

View File

@ -26,8 +26,6 @@ pub fn clone_tls(image: &TlsImage) -> Result<(usize, usize), Error> {
panic!("TODO: TLS alignment larger than a page size is not supported");
}
let align = image.align;
// TCB size, padded to align. Also the start of the first module
let tcb_aligned_size = (TCB_SIZE + image.align - 1) & !(image.align - 1);
let full_size = tcb_aligned_size + image.full_size;

View File

@ -23,8 +23,8 @@ mod generated {
mem::{MappingFlags, MappingSource},
net::SocketType,
process::{
ExecveOptions, ProcessGroupId, ProcessId, ProcessOption, Signal, SignalEntryData,
SpawnOptions, ThreadSpawnOptions, WaitFlags,
ExecveOptions, ProcessGroupId, ProcessId, Signal, SignalEntryData, SpawnOptions,
ThreadSpawnOptions, WaitFlags,
},
SyscallFunction,
};

View File

@ -1,14 +1,19 @@
use std::{io, os::{fd::{AsRawFd, RawFd}, yggdrasil::io::pid::{PidFd as YggPidFd, ProcessId}}};
use std::{
io,
os::{
fd::{AsRawFd, RawFd},
yggdrasil::io::pid::{PidFd as YggPidFd, ProcessId},
},
};
use crate::sys::PidFd;
pub struct PidFdImpl(YggPidFd);
impl PidFd for PidFdImpl {
fn new(pid: u32) -> io::Result<Self> {
let pid = unsafe { ProcessId::from_raw(pid) };
YggPidFd::new(pid).map(Self)
YggPidFd::child(pid, false).map(Self)
}
fn exit_status(&self) -> io::Result<i32> {

View File

@ -12,8 +12,7 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, OptionExt},
headers::{
errno,
string::mem::{memcpy, memset},
errno::Errno, string::mem::{memcpy, memset}
},
};
@ -80,7 +79,7 @@ pub fn c_alloc(size: usize, align: usize, zero: bool) -> EResult<NonNull<c_void>
};
let size = size + 16;
let layout = Layout::from_size_align(size, align).expect("Couldn't setup malloc() layout");
let ptr = YALLOC.lock().allocate(layout).e_ok_or(errno::ENOMEM)?;
let ptr = YALLOC.lock().allocate(layout).e_ok_or(Errno::ENOMEM)?;
if zero {
unsafe {

View File

@ -13,8 +13,7 @@ use crate::{
allocator::{c_alloc, c_free},
error::EResult,
headers::{
errno,
string::{mem::memcpy, str::strlen},
errno::Errno, string::{mem::memcpy, str::strlen}
},
thread,
util::PointerExt,
@ -63,7 +62,7 @@ unsafe fn push_env(str: NonNull<c_char>) -> EResult<()> {
reclaim_env()?;
if shadow.try_reserve(1).is_err() {
return EResult::Err(errno::ENOMEM);
return EResult::Err(Errno::ENOMEM);
}
let entry = shadow.last_mut().unwrap();
@ -81,7 +80,7 @@ unsafe fn push_env(str: NonNull<c_char>) -> EResult<()> {
pub unsafe fn get_env(name: &[u8]) -> EResult<Option<NonNull<c_char>>> {
if name.is_empty() || name.contains(&b'=') {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
let Some(mut iter) = NonNull::new(environ) else {
@ -106,7 +105,7 @@ pub unsafe fn get_env(name: &[u8]) -> EResult<Option<NonNull<c_char>>> {
pub unsafe fn set_env(name: &[u8], value: NonNull<c_char>, overwrite: bool) -> EResult<()> {
if name.is_empty() || name.contains(&b'=') {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
let value = CStr::from_ptr(value.as_ptr()).to_bytes();
@ -153,7 +152,7 @@ pub unsafe fn set_env(name: &[u8], value: NonNull<c_char>, overwrite: bool) -> E
pub unsafe fn remove_env(name: &[u8]) -> EResult<bool> {
if name.is_empty() || name.contains(&b'=') {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
reclaim_env()?;
@ -180,7 +179,7 @@ pub unsafe fn remove_env(name: &[u8]) -> EResult<bool> {
pub unsafe fn put_env(str: NonNull<c_char>) -> EResult<()> {
let bytes = CStr::from_ptr(str.as_ptr()).to_bytes();
if bytes.is_empty() || !bytes.contains(&b'=') {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
let name = get_key(str).unwrap();

View File

@ -26,7 +26,7 @@ macro impl_from_residual($($ty:ty),+) {
#[thread_local]
#[no_mangle]
#[allow(non_upper_case_globals)]
pub static mut errno: Errno = Errno(0);
pub static mut errno: Errno = Errno::ESUCCESS;
pub trait ResultExt<T, E> {
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T>;

View File

@ -13,7 +13,7 @@ use crate::{
util::{PointerExt, PointerStrExt},
};
use super::{errno::ESUCCESS, sys_types::ino_t};
use super::{errno::Errno, sys_types::ino_t};
#[derive(Debug)]
#[repr(C)]
@ -46,7 +46,7 @@ impl DIR {
self.buffer.write(dirent::from(entry));
EResult::Ok(unsafe { NonNull::new_unchecked(self.buffer.as_mut_ptr()) })
}
EResult::Ok(None) => EResult::Err(ESUCCESS),
EResult::Ok(None) => EResult::Err(Errno::ESUCCESS),
EResult::Err(err) => EResult::Err(err),
}
}

View File

@ -15,7 +15,7 @@ pub struct Dl_info {
}
#[no_mangle]
unsafe extern "C" fn dlclose(dl: *mut c_void) -> c_int {
unsafe extern "C" fn dlclose(_dl: *mut c_void) -> c_int {
todo!()
}
@ -25,26 +25,26 @@ unsafe extern "C" fn dlerror() -> *mut c_char {
}
#[no_mangle]
unsafe extern "C" fn dlopen(path: *const c_char, flags: c_int) -> *mut c_void {
unsafe extern "C" fn dlopen(_path: *const c_char, _flags: c_int) -> *mut c_void {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dlsym(dl: *mut c_void, name: *const c_char) -> *mut c_void {
unsafe extern "C" fn dlsym(_dl: *mut c_void, _name: *const c_char) -> *mut c_void {
todo!()
}
// Non-POSIX
#[no_mangle]
unsafe extern "C" fn dladdr(addr: *mut c_void, info: *mut Dl_info) -> c_int {
unsafe extern "C" fn dladdr(_addr: *mut c_void, _info: *mut Dl_info) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn dladdr1(
addr: *mut c_void,
info: *mut Dl_info,
extra_info: *mut *mut c_void,
flags: c_int,
_addr: *mut c_void,
_info: *mut Dl_info,
_extra_info: *mut *mut c_void,
_flags: c_int,
) -> c_int {
todo!()
}

View File

@ -7,4 +7,8 @@ no_includes = true
include_guard = "_ERRNO_H"
trailer = "#include <bits/errno.h>"
[enum]
enum_style = "define"
[export]
include = ["Errno"]

View File

@ -1,187 +1,200 @@
use core::ffi::{c_int, CStr};
use core::ffi::CStr;
macro_rules! static_cstr {
($string:expr) => {
unsafe {
::core::ffi::CStr::from_bytes_with_nul_unchecked(concat!($string, "\0").as_bytes())
}
};
macro static_cstr($string:literal) {
unsafe { ::core::ffi::CStr::from_bytes_with_nul_unchecked(concat!($string, "\0").as_bytes()) }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[repr(transparent)]
pub struct Errno(pub c_int);
#[non_exhaustive]
#[repr(C)]
pub enum Errno {
ESUCCESS = 0,
EPERM = 1,
ENOENT = 2,
ESRCH = 3,
EINTR = 4,
EIO = 5,
ENXIO = 6,
E2BIG = 7,
ENOEXEC = 8,
EBADF = 9,
ECHILD = 10,
EAGAIN = 11,
ENOMEM = 12,
EACCES = 13,
EFAULT = 14,
ENOTBLK = 15,
EBUSY = 16,
EEXIST = 17,
EXDEV = 18,
ENODEV = 19,
ENOTDIR = 20,
EISDIR = 21,
EINVAL = 22,
ENFILE = 23,
EMFILE = 24,
ENOTTY = 25,
ETXTBSY = 26,
EFBIG = 27,
ENOSPC = 28,
ESPIPE = 29,
EROFS = 30,
EMLINK = 31,
EPIPE = 32,
EDOM = 33,
ERANGE = 34,
pub const ESUCCESS: Errno = Errno(0);
pub const EPERM: Errno = Errno(1);
pub const ENOENT: Errno = Errno(2);
pub const ESRCH: Errno = Errno(3);
pub const EINTR: Errno = Errno(4);
pub const EIO: Errno = Errno(5);
pub const ENXIO: Errno = Errno(6);
pub const E2BIG: Errno = Errno(7);
pub const ENOEXEC: Errno = Errno(8);
pub const EBADF: Errno = Errno(9);
pub const ECHILD: Errno = Errno(10);
pub const EAGAIN: Errno = Errno(11);
pub const ENOMEM: Errno = Errno(12);
pub const EACCES: Errno = Errno(13);
pub const EFAULT: Errno = Errno(14);
pub const ENOTBLK: Errno = Errno(15);
pub const EBUSY: Errno = Errno(16);
pub const EEXIST: Errno = Errno(17);
pub const EXDEV: Errno = Errno(18);
pub const ENODEV: Errno = Errno(19);
pub const ENOTDIR: Errno = Errno(20);
pub const EISDIR: Errno = Errno(21);
pub const EINVAL: Errno = Errno(22);
pub const ENFILE: Errno = Errno(23);
pub const EMFILE: Errno = Errno(24);
pub const ENOTTY: Errno = Errno(25);
pub const ETXTBSY: Errno = Errno(26);
pub const EFBIG: Errno = Errno(27);
pub const ENOSPC: Errno = Errno(28);
pub const ESPIPE: Errno = Errno(29);
pub const EROFS: Errno = Errno(30);
pub const EMLINK: Errno = Errno(31);
pub const EPIPE: Errno = Errno(32);
pub const EDOM: Errno = Errno(33);
pub const ERANGE: Errno = Errno(34);
EDEADLK = 35,
ENAMETOOLONG = 36,
ENOLCK = 37,
pub const EDEADLK: Errno = Errno(35);
pub const ENAMETOOLONG: Errno = Errno(36);
ENOSYS = 38,
ENOTEMPTY = 39,
ELOOP = 40,
pub const ENOLCK: Errno = Errno(37);
pub const ENOSYS: Errno = Errno(38);
pub const ENOTEMPTY: Errno = Errno(39);
pub const ELOOP: Errno = Errno(40);
pub const EWOULDBLOCK: Errno = EAGAIN;
pub const ENOMSG: Errno = Errno(42);
ENOTSOCK = 41,
EDESTADDRREQ = 42,
EMSGSIZE = 43,
EPROTOTYPE = 44,
ENOPROTOOPT = 45,
EPROTONOSUPPORT = 46,
ESOCKTNOSUPPORT = 47,
EOPNOTSUPP = 48,
EPFNOSUPPORT = 49,
EAFNOSUPPORT = 50,
EADDRINUSE = 51,
EADDRNOTAVAIL = 52,
ENETDOWN = 53,
ENETUNREACH = 54,
ENETRESET = 55,
ECONNABORTED = 56,
ECONNRESET = 57,
ENOBUFS = 58,
EISCONN = 59,
ENOTCONN = 60,
ESHUTDOWN = 61,
ETIMEDOUT = 62,
ECONNREFUSED = 63,
EHOSTDOWN = 64,
EHOSTUNREACH = 65,
// Custom errnos
ENOTSUPP = 66,
ETIMEOUT = 67,
}
pub const MAX_ERROR: Errno = ERANGE;
static SUCCESS: &CStr = static_cstr!("Success");
pub static UNKNOWN_ERROR: &CStr = static_cstr!("Unknown error");
static UNKNOWN_ERROR: &CStr = static_cstr!("Unknown error");
static ERRNO_STRINGS: &[&CStr] = &[
// 0
SUCCESS,
// EPERM 1
static_cstr!("No error"),
static_cstr!("Operation not permitted"),
// ENOENT 2
static_cstr!("No such file or directory"),
// ESRCH 3
static_cstr!("No such process"),
// EINTR 4
static_cstr!("Interrupted system call"),
// EIO 5
static_cstr!("Input/output error"),
// ENXIO 6
static_cstr!("I/O error"),
static_cstr!("No such device or address"),
// E2BIG 7
static_cstr!("Argument list too long"),
// ENOEXEC 8
static_cstr!("Exec format error"),
// EBADF 9
static_cstr!("Bad file descriptor"),
// ECHILD 10
static_cstr!("No child processses"),
// EAGAIN 11
static_cstr!("Resource temporarily unavailable"),
// ENOMEM 12
static_cstr!("Cannot allocate memory"),
// EACCES 13
static_cstr!("Bad file number"),
static_cstr!("No child process"),
static_cstr!("Try again"),
static_cstr!("Out of memory"),
static_cstr!("Permission denied"),
// EFAULT 14
static_cstr!("Bad address"),
// ENOTBLK 15
static_cstr!("Block device required"),
// EBUSY 16
static_cstr!("Device or resource busy"),
// EEXIST 17
static_cstr!("File exists"),
// EXDEV 18
static_cstr!("Invalid cross-device link"),
// ENODEV 19
static_cstr!("Cross-device link"),
static_cstr!("No such device"),
// ENOTDIR 20
static_cstr!("Not a directory"),
// EISDIR 21
static_cstr!("Is a directory"),
// EINVAL 22
static_cstr!("Invalid argument"),
// ENFILE 23
static_cstr!("Too many open files in system"),
// EMFILE 24
static_cstr!("File table overflow"),
static_cstr!("Too many open files"),
// ENOTTY 25
static_cstr!("Inappropriate ioctl for device"),
// ETXTBSY 26
static_cstr!("Not a typewriter"),
static_cstr!("Text file busy"),
// EFBIG 27
static_cstr!("File too large"),
// ENOSPC 28
static_cstr!("No space left on device"),
// ESPIPE 29
static_cstr!("Illegal seek"),
// EROFS 30
static_cstr!("Read-only file system"),
// EMLINK 31
static_cstr!("Too many links"),
// EPIPE 32
static_cstr!("Broken pipe"),
// EDOM 33
static_cstr!("Numerical argument out of domain"),
// ERANGE 34
static_cstr!("Numerical result out of range"),
static_cstr!("Math argument out of domain of func"),
static_cstr!("Math result not representable"),
static_cstr!("Resource deadlock would occur"),
static_cstr!("File name too long"),
static_cstr!("No record locks available"),
static_cstr!("Invalid system call number"),
static_cstr!("Directory not empty"),
static_cstr!("Too many symbolic links encountered"),
static_cstr!("Socket operation on non-socket"),
static_cstr!("Destination address required"),
static_cstr!("Message too long"),
static_cstr!("Protocol wrong type for socket"),
static_cstr!("Protocol not available"),
static_cstr!("Protocol not supported"),
static_cstr!("Socket type not supported"),
static_cstr!("Operation not supported on transport endpoint"),
static_cstr!("Protocol family not supported"),
static_cstr!("Address family not supported by protocol"),
static_cstr!("Address already in use"),
static_cstr!("Cannot assign requested address"),
static_cstr!("Network is down"),
static_cstr!("Network is unreachable"),
static_cstr!("Network dropped connection because of reset"),
static_cstr!("Software caused connection abort"),
static_cstr!("Connection reset by peer"),
static_cstr!("No buffer space available"),
static_cstr!("Transport endpoint is already connected"),
static_cstr!("Transport endpoint is not connected"),
static_cstr!("Cannot send after transport endpoint shutdown"),
static_cstr!("Connection timed out"),
static_cstr!("Connection refused"),
static_cstr!("Host is down"),
static_cstr!("No route to host"),
// Custom errnos
static_cstr!("Operation not supported"),
static_cstr!("Operation timed out"),
];
impl Errno {
pub fn to_c_str(&self) -> &CStr {
ERRNO_STRINGS
.get(self.0 as usize)
.copied()
.unwrap_or(SUCCESS)
}
pub fn from_c_int(v: c_int) -> Option<Self> {
if !(0..=MAX_ERROR.0).contains(&v) {
None
} else {
Some(Self(v))
}
pub fn to_c_str(self) -> &'static CStr {
let index = self as usize;
ERRNO_STRINGS.get(index).copied().unwrap_or(UNKNOWN_ERROR)
}
}
impl From<yggdrasil_rt::Error> for Errno {
fn from(value: yggdrasil_rt::Error) -> Self {
use yggdrasil_rt::Error as E;
use yggdrasil_rt::Error;
match value {
E::TimedOut => todo!(),
E::MissingData => todo!(),
// TODO ???
E::InvalidMemoryOperation => EPERM,
// TODO ???
E::NotImplemented => EPERM,
// TODO ???
E::DirectoryNotEmpty => EISDIR,
// TODO ???
E::WouldBlock => EAGAIN,
// TODO ???
E::InvalidOperation => EPERM,
E::DoesNotExist => ENOENT,
E::AlreadyExists => EEXIST,
E::InvalidArgument => EINVAL,
E::NotADirectory => ENOTDIR,
E::PermissionDenied => EACCES,
E::UnrecognizedExecutable => ENOEXEC,
E::ReadOnly => EROFS,
E::OutOfMemory => ENOMEM,
E::InvalidFile => EBADF,
E::Interrupted => EINTR,
E::IsADirectory => EISDIR,
_ => todo!()
Error::OutOfMemory => Errno::ENOMEM,
Error::AlreadyExists => Errno::EEXIST,
Error::NotImplemented => Errno::ENOTSUPP,
Error::DoesNotExist => Errno::ENOENT,
Error::InvalidFile => Errno::EBADF,
Error::InvalidArgument => Errno::EINVAL,
Error::Interrupted => Errno::EINTR,
Error::WouldBlock => Errno::EAGAIN,
Error::UnrecognizedExecutable => Errno::ENOEXEC,
Error::InvalidOperation => Errno::EPERM,
Error::InvalidMemoryOperation => Errno::EPERM,
Error::NotADirectory => Errno::ENOTDIR,
Error::IsADirectory => Errno::EISDIR,
Error::ReadOnly => Errno::EROFS,
Error::PermissionDenied => Errno::EACCES,
Error::AddrInUse => Errno::EADDRINUSE,
Error::QueueFull => Errno::ENOBUFS,
Error::BufferTooSmall => Errno::ENOMEM,
Error::ConnectionReset => Errno::ECONNRESET,
Error::MissingData => Errno::EINVAL,
Error::NetworkUnreachable => Errno::ENETUNREACH,
Error::TimedOut => Errno::ETIMEOUT,
Error::ConnectionRefused => Errno::ECONNREFUSED,
Error::HostUnreachable => Errno::EHOSTUNREACH,
Error::UndefinedSyscall => Errno::ENOSYS,
Error::DirectoryNotEmpty => Errno::ENOTEMPTY,
Error::NotConnected => Errno::ENOTCONN,
Error::ProcessNotFound => Errno::ESRCH,
}
}
}

View File

@ -9,7 +9,7 @@ use crate::{
};
use super::{
errno,
errno::Errno,
sys_types::{mode_t, off_t, pid_t},
};
@ -107,7 +107,7 @@ fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> {
O_EXEC => todo!(),
O_SEARCH => todo!(),
_ => {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
}
@ -182,10 +182,10 @@ unsafe extern "C" fn openat(
#[no_mangle]
unsafe extern "C" fn faccessat(
atfd: c_int,
path: *const c_char,
mode: c_int,
flags: c_int,
_atfd: c_int,
_path: *const c_char,
_mode: c_int,
_flags: c_int,
) -> c_int {
todo!()
}

View File

@ -6,11 +6,7 @@ use core::{
use crate::{
error::{self, CIntZeroResult, CResult, OptionExt},
headers::{
errno,
pthread::{PTHREAD_CREATE_JOINABLE, PTHREAD_INHERIT_SCHED, PTHREAD_SCOPE_PROCESS},
sched::{__ygg_sched_param_t, SCHED_RR},
sys_time::timespec,
sys_types::pthread_attr_t,
errno::Errno, pthread::{PTHREAD_CREATE_JOINABLE, PTHREAD_INHERIT_SCHED, PTHREAD_SCOPE_PROCESS}, sched::{__ygg_sched_param_t, SCHED_RR}, sys_time::timespec, sys_types::pthread_attr_t
},
thread,
util::PointerExt,
@ -192,13 +188,13 @@ unsafe extern "C" fn pthread_attr_setstack(
size: usize,
) -> CIntZeroResult {
let attr = attr.ensure_mut();
let stack = NonNull::new(stack).e_ok_or(errno::EINVAL)?;
let stack = NonNull::new(stack).e_ok_or(Errno::EINVAL)?;
if size >= thread::MIN_STACK_SIZE {
attr.stack = Some(stack);
attr.stack_size = size;
CIntZeroResult::SUCCESS
} else {
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}
@ -213,7 +209,7 @@ unsafe extern "C" fn pthread_attr_setstacksize(
attr.stack_size = size;
CIntZeroResult::SUCCESS
} else {
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}

View File

@ -11,7 +11,7 @@ use yggdrasil_rt::process::MutexOperation;
use crate::{
error::{self, CIntZeroResult, CResult},
headers::{
errno,
errno::Errno,
sys_types::{pthread_barrier_t, pthread_barrierattr_t},
},
util::PointerExt,
@ -113,7 +113,7 @@ unsafe extern "C" fn pthread_barrierattr_setpshared(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_barrierattr_setpshared()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}

View File

@ -7,7 +7,7 @@ use yggdrasil_rt::process::MutexOperation;
use crate::{
error::{self, CIntZeroResult, CResult, EResult},
headers::{
errno,
errno::Errno,
sys_time::__ygg_timespec_t,
sys_types::{clockid_t, pthread_cond_t, pthread_condattr_t, pthread_mutex_t},
time::CLOCK_MONOTONIC,
@ -151,7 +151,7 @@ unsafe extern "C" fn pthread_condattr_setclock(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_condattr_setclock()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}
@ -165,7 +165,7 @@ unsafe extern "C" fn pthread_condattr_setpshared(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_condattr_setpshared()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}

View File

@ -1,15 +1,11 @@
use core::{
ffi::c_int,
ptr::NonNull,
sync::atomic::{AtomicU32, Ordering},
};
use core::{ffi::c_int, ptr::NonNull, sync::atomic::Ordering};
use yggdrasil_rt::process::MutexOperation;
use crate::{
error::{self, CIntZeroResult, CResult, EResult},
headers::{
errno,
errno::Errno,
pthread::{
PTHREAD_MUTEX_NORMAL, PTHREAD_MUTEX_STALLED, PTHREAD_PRIO_NONE, PTHREAD_PROCESS_PRIVATE,
},
@ -25,22 +21,6 @@ use super::{PTHREAD_MUTEX_DEFAULT, PTHREAD_MUTEX_RECURSIVE};
impl pthread_mutex_t {
const LOCKED: u32 = 1;
// fn new() -> EResult<Self> {
// Self::new_with(&pthread_mutexattr_t::default())
// }
// fn new_with(attr: &pthread_mutexattr_t) -> EResult<Self> {
// match attr.__mode {
// PTHREAD_MUTEX_NORMAL | PTHREAD_MUTEX_RECURSIVE => (),
// _ => return EResult::Err(errno::EINVAL)
// }
// EResult::Ok(Self {
// __mode: attr.__mode,
// __state: AtomicU32::new(0),
// __recursion: AtomicU32::new(0)
// })
// }
fn try_lock(&self) -> EResult<bool> {
match self.__mode {
PTHREAD_MUTEX_NORMAL => EResult::Ok(
@ -54,23 +34,26 @@ impl pthread_mutex_t {
thread_id = u32::MAX;
}
match self.__state.compare_exchange(0, thread_id, Ordering::Acquire, Ordering::Relaxed) {
match self.__state.compare_exchange(
0,
thread_id,
Ordering::Acquire,
Ordering::Relaxed,
) {
// 0 -> thread_id
Ok(_) => {
self.__recursion.fetch_add(1, Ordering::Relaxed);
EResult::Ok(true)
},
}
Err(t) if t == thread_id => {
self.__recursion.fetch_add(1, Ordering::Relaxed);
EResult::Ok(true)
}
// Other thread owns the lock
Err(_) => {
EResult::Ok(false)
}
Err(_) => EResult::Ok(false),
}
}
_ => EResult::Err(errno::EINVAL),
_ => EResult::Err(Errno::EINVAL),
}
}
@ -78,7 +61,7 @@ impl pthread_mutex_t {
if self.try_lock()? {
EResult::Ok(())
} else {
EResult::Err(errno::EBUSY)
EResult::Err(Errno::EBUSY)
}
}
@ -114,8 +97,8 @@ impl pthread_mutex_t {
yggdrasil_rt::sys::mutex(&self.__state, &MutexOperation::Wake(1)).ok();
}
EResult::Ok(())
},
_ => EResult::Err(errno::EINVAL),
}
_ => EResult::Err(Errno::EINVAL),
}
}
}
@ -123,7 +106,7 @@ impl pthread_mutex_t {
impl Default for pthread_mutexattr_t {
fn default() -> Self {
Self {
__mode: PTHREAD_MUTEX_DEFAULT
__mode: PTHREAD_MUTEX_DEFAULT,
}
}
}
@ -303,7 +286,7 @@ unsafe extern "C" fn pthread_mutexattr_setprotocol(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setprotocol()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}
@ -317,7 +300,7 @@ unsafe extern "C" fn pthread_mutexattr_setpshared(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setpshared()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}
@ -331,7 +314,7 @@ unsafe extern "C" fn pthread_mutexattr_setrobust(
CIntZeroResult::SUCCESS
} else {
yggdrasil_rt::debug_trace!("TODO: pthread_mutexattr_setrobust()");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}
@ -348,7 +331,7 @@ unsafe extern "C" fn pthread_mutexattr_settype(
CIntZeroResult::SUCCESS
}
_ => {
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
CIntZeroResult::ERROR
}
}

View File

@ -4,7 +4,7 @@ use yggdrasil_rt::process::thread_local;
use crate::{
error::{self, CIntZeroResult, ResultExt},
headers::{errno, sys_types::pthread_key_t},
headers::{errno::Errno, sys_types::pthread_key_t},
util::PointerExt,
};
@ -29,13 +29,13 @@ unsafe extern "C" fn pthread_key_delete(_key: pthread_key_t) -> CIntZeroResult {
unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
let dtv = thread_local::get_dtv();
if key == 0 {
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
return null_mut();
}
match dtv.get_specific(key) {
Some(value) => value,
None => {
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
null_mut()
}
}
@ -45,6 +45,6 @@ unsafe extern "C" fn pthread_getspecific(key: pthread_key_t) -> *mut c_void {
unsafe extern "C" fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> CIntZeroResult {
let dtv = thread_local::get_dtv();
dtv.try_set_specific(key, value, false)
.e_map_err(|_| errno::EINVAL)?;
.e_map_err(|_| Errno::EINVAL)?;
CIntZeroResult::SUCCESS
}

View File

@ -1,11 +1,20 @@
use core::{ffi::{c_char, c_int, c_long, c_void}, ptr::NonNull};
use core::{
ffi::{c_char, c_int, c_long, c_void},
ptr::NonNull,
};
use yggdrasil_rt::process::{Signal, signal as rt};
use yggdrasil_rt::process::{signal as rt, Signal};
use crate::{error::{self, CIntZeroResult, CResult, EResult, TryFromExt}, signal, util::PointerExt};
use crate::{
error::{self, CIntZeroResult, CResult, EResult, TryFromExt},
headers::errno::Errno,
signal,
util::PointerExt,
};
use super::{
errno, sys_time::__ygg_timespec_t, sys_types::{pid_t, uid_t}
sys_time::__ygg_timespec_t,
sys_types::{pid_t, uid_t},
};
pub type sig_handler_t = unsafe extern "C" fn(SigNumber);
@ -134,7 +143,7 @@ impl TryFromExt<SigNumber> for Signal {
SigNumber::SIGILL => EResult::Ok(Signal::InvalidInstruction),
SigNumber::SIGKILL => EResult::Ok(Signal::Killed),
SigNumber::SIGTERM => EResult::Ok(Signal::Terminated),
_ => EResult::Err(errno::EINVAL)
_ => EResult::Err(Errno::EINVAL),
}
}
}
@ -149,7 +158,7 @@ impl From<Signal> for SigNumber {
Signal::Killed => Self::SIGKILL,
Signal::Terminated => Self::SIGTERM,
// Never issued/handled
Signal::Debug => unreachable!()
Signal::Debug => unreachable!(),
}
}
}
@ -213,12 +222,16 @@ unsafe extern "C" fn sigaddset(_mask: *mut sigset_t, _signum: c_int) -> c_int {
unsafe extern "C" fn sigaltstack(new: *const stack_t, old: *mut stack_t) -> CIntZeroResult {
if let Some(old) = NonNull::new(old) {
let (base, size) = rt::get_signal_stack();
old.write(stack_t { ss_sp: base as _, ss_flags: 0, ss_size: size });
old.write(stack_t {
ss_sp: base as _,
ss_flags: 0,
ss_size: size,
});
}
if let Some(new) = new.as_ref() {
// TODO what do with SS_DISABLE?
if new.ss_size < MINSIGSTKSZ {
error::errno = errno::ENOMEM;
error::errno = Errno::ENOMEM;
return CIntZeroResult::ERROR;
}
rt::set_signal_stack(new.ss_sp.addr(), new.ss_size);
@ -270,7 +283,7 @@ unsafe extern "C" fn signal(handler: sig_handler_t, signum: SigNumber) -> sig_ha
// NULL or SIG_ERR
if address == 0 || address == 1 {
yggdrasil_rt::debug_trace!("libc: signal() was passed an invalid handler");
error::errno = errno::EINVAL;
error::errno = Errno::EINVAL;
// SIG_ERR
return core::mem::transmute(1usize);
}

View File

@ -15,7 +15,7 @@ use crate::{
CEofResult, CFdResult, CIntZeroResult, COffsetResult, CPtrResult, CResult, EResult,
ResultExt, TryFromExt,
},
headers::{errno, sys_types::off_t},
headers::{errno::Errno, sys_types::off_t},
io::{
self,
managed::{FileOpenSource, FILE},
@ -148,7 +148,7 @@ unsafe extern "C" fn fopen(path: *const c_char, mode: *const c_char) -> CPtrResu
#[no_mangle]
unsafe extern "C" fn fseek(fp: *mut FILE, offset: c_long, whence: c_int) -> CIntZeroResult {
let offset: off_t = offset.try_into().e_map_err(|_| errno::EINVAL)?;
let offset: off_t = offset.try_into().e_map_err(|_| Errno::EINVAL)?;
fseeko(fp, offset, whence)
}

View File

@ -8,7 +8,7 @@ use core::{
use crate::{
allocator,
error::{CEofResult, CIsizeResult, CPtrResult, CResult, EResult},
headers::errno,
headers::errno::Errno,
io::{
managed::{stdin, stdout, FILE},
Read, Write,
@ -154,8 +154,8 @@ unsafe extern "C" fn puts(str: *const c_char) -> CEofResult {
yggdrasil_rt::sys::write(RawFd::STDOUT, b"\n").ok();
}
return CEofResult::success(0)
},
return CEofResult::success(0);
}
};
out.write_all(str.to_bytes())?;
out.write_all(b"\n")?;
@ -241,7 +241,7 @@ fn getdelim_inner(
if writer.position == 0 {
// EOF reached before anything could be read
return (writer, EResult::Err(errno::ESUCCESS));
return (writer, EResult::Err(Errno::ESUCCESS));
}
match writer.putc(0) {

View File

@ -2,7 +2,7 @@ use core::{ffi::c_double, fmt, num::FpCategory};
use alloc::{format, string::String};
use crate::{error::EResult, headers::errno, io::Write};
use crate::{error::EResult, headers::errno::Errno, io::Write};
use super::format::FmtOpts;
@ -49,7 +49,7 @@ fn fmt_float_exp<W: Write + fmt::Write>(
match write!(output, "{}{:+03}", exp_fmt as char, exp) {
Ok(()) => (),
// TODO proper error code
Err(_) => return EResult::Err(errno::EINVAL),
Err(_) => return EResult::Err(Errno::EINVAL),
};
EResult::Ok(f_len + 2 + 2.max(exp_len))

View File

@ -6,8 +6,9 @@ use reader::{GetChar, ScanReader};
use crate::{
error::{CEofResult, EResult},
headers::errno::{self, Errno},
io::managed::{stdin, FILE}, util::{PointerExt, PointerStrExt},
headers::errno::Errno,
io::managed::{stdin, FILE},
util::{PointerExt, PointerStrExt},
};
mod char_set;
@ -121,7 +122,7 @@ fn scanf_inner<G: GetChar>(
b'[' => {
let (new_it, set) = match ScanCharSet::from_format_iter(it) {
Ok(v) => v,
Err(FormatError) => return EResult::Err(errno::ESUCCESS),
Err(FormatError) => return EResult::Err(Errno::ESUCCESS),
};
it = new_it;
ScanSpec::Chars(set)
@ -132,11 +133,11 @@ fn scanf_inner<G: GetChar>(
b'%' => ScanSpec::Percent,
b'f' | b'e' | b'g' | b'E' | b'a' => todo!(),
// Unrecognized specifier
_ => return EResult::Err(errno::ESUCCESS),
_ => return EResult::Err(Errno::ESUCCESS),
}
} else {
// No specifier after %
return EResult::Err(errno::ESUCCESS);
return EResult::Err(Errno::ESUCCESS);
};
matched += match opts.scan(stream, spec, &mut ap) {
@ -157,11 +158,7 @@ unsafe extern "C" fn scanf(format: *const c_char, mut args: ...) -> CEofResult {
}
#[no_mangle]
unsafe extern "C" fn fscanf(
fp: *mut FILE,
format: *const c_char,
mut args: ...
) -> CEofResult {
unsafe extern "C" fn fscanf(fp: *mut FILE, format: *const c_char, mut args: ...) -> CEofResult {
vfscanf(fp, format, args.as_va_list())
}
@ -171,11 +168,7 @@ unsafe extern "C" fn vscanf(format: *const c_char, args: VaList) -> CEofResult {
}
#[no_mangle]
unsafe extern "C" fn vfscanf(
fp: *mut FILE,
format: *const c_char,
args: VaList,
) -> CEofResult {
unsafe extern "C" fn vfscanf(fp: *mut FILE, format: *const c_char, args: VaList) -> CEofResult {
let fp = fp.ensure_mut();
let format = format.ensure_cstr();
let mut reader = ScanReader::new(fp);

View File

@ -6,12 +6,12 @@ use core::{
use crate::{
allocator,
error::{CPtrResult, OptionExt},
headers::errno,
headers::errno::Errno,
};
#[no_mangle]
unsafe extern "C" fn calloc(size: usize, nmemb: usize) -> CPtrResult<c_void> {
let size = size.checked_mul(nmemb).e_ok_or(errno::ENOMEM)?;
let size = size.checked_mul(nmemb).e_ok_or(Errno::ENOMEM)?;
let ptr = allocator::c_alloc(size, 16, true)?;
CPtrResult::success(ptr)
}

View File

@ -4,11 +4,7 @@ use core::{
};
use crate::{
env,
error::{CIntZeroResult, CPtrResult, CResult, OptionExt},
headers::errno,
process,
util::PointerStrExt,
env, error::{CIntZeroResult, CPtrResult, CResult, OptionExt}, headers::errno::Errno, process, util::PointerStrExt
};
#[no_mangle]
@ -45,7 +41,7 @@ unsafe extern "C" fn getenv(name: *const c_char) -> CPtrResult<c_char> {
#[no_mangle]
unsafe extern "C" fn putenv(value: *mut c_char) -> CIntZeroResult {
let value = NonNull::new(value).e_ok_or(errno::EINVAL)?;
let value = NonNull::new(value).e_ok_or(Errno::EINVAL)?;
env::put_env(value)?;
CIntZeroResult::SUCCESS
}
@ -57,7 +53,7 @@ unsafe extern "C" fn setenv(
overwrite: c_int,
) -> CIntZeroResult {
let name = name.ensure_cstr().to_bytes();
let value = NonNull::new(value.cast_mut()).e_ok_or(errno::EINVAL)?;
let value = NonNull::new(value.cast_mut()).e_ok_or(Errno::EINVAL)?;
let overwrite = overwrite != 0;
env::set_env(name, value, overwrite)?;
CIntZeroResult::SUCCESS

View File

@ -1,7 +1,7 @@
language = "C"
style = "Type"
sys_includes = ["stddef.h", "locale.h", "strings.h"]
sys_includes = ["stddef.h", "locale.h", "strings.h", "errno.h"]
no_includes = true
include_guard = "_STRING_H"

View File

@ -7,10 +7,7 @@ use core::{
use crate::{
allocator,
error::CPtrResult,
headers::{
errno::{self, Errno},
locale::locale_t,
},
headers::{errno::Errno, locale::locale_t},
};
use super::mem::{memcpy, mempcpy, memset};
@ -99,23 +96,19 @@ unsafe extern "C" fn strdup(s: *const c_char) -> CPtrResult<c_char> {
CPtrResult::success(data.cast())
}
unsafe fn strerror_inner(e: c_int) -> *const c_char {
if let Some(errno) = Errno::from_c_int(e) {
errno.to_c_str().as_ptr()
} else {
errno::UNKNOWN_ERROR.as_ptr()
}
unsafe fn strerror_inner(e: Errno) -> *const c_char {
e.to_c_str().as_ptr()
}
#[no_mangle]
unsafe extern "C" fn strerror(e: c_int) -> *mut c_char {
unsafe extern "C" fn strerror(e: Errno) -> *mut c_char {
static mut BUF: [c_char; 128] = [0; 128];
#[allow(static_mut_refs)]
strerror_r(e, BUF.as_mut_ptr(), BUF.len())
}
#[no_mangle]
unsafe extern "C" fn strerror_r(e: c_int, buf: *mut c_char, n: usize) -> *mut c_char {
unsafe extern "C" fn strerror_r(e: Errno, buf: *mut c_char, n: usize) -> *mut c_char {
let source = strerror_inner(e);
strncpy(buf, source, n)
}

View File

@ -1,4 +1,4 @@
use core::{ffi::{c_char, c_int, c_void}, ptr::null_mut};
use core::ffi::{c_char, c_int, c_void};
use crate::error::CPtrResult;

View File

@ -2,8 +2,9 @@ use core::{ffi::c_double, time::Duration};
use crate::{
error::{self, CIntZeroResult, CResult},
headers::{errno, sys_time::__ygg_timespec_t, sys_types::time_t},
process, util::PointerExt,
headers::{errno::Errno, sys_time::__ygg_timespec_t, sys_types::time_t},
process,
util::PointerExt,
};
#[no_mangle]
@ -15,14 +16,12 @@ unsafe extern "C" fn nanosleep(
let amount = Duration::from(*rqtp);
match process::sleep(amount) {
Ok(()) => {
CIntZeroResult::SUCCESS
}
Ok(()) => CIntZeroResult::SUCCESS,
Err(remaining) => {
if let Some(rmtp) = rmtp.as_mut() {
*rmtp = remaining.into();
}
error::errno = errno::EINTR;
error::errno = Errno::EINTR;
CIntZeroResult::ERROR
}
}

View File

@ -7,7 +7,10 @@ use yggdrasil_rt::debug_trace;
use crate::{
error::{self, CIntCountResult, CIntZeroResult, ResultExt},
headers::{errno, sys_types::{gid_t, pid_t, uid_t}},
headers::{
errno::Errno,
sys_types::{gid_t, pid_t, uid_t},
},
process,
};
@ -132,7 +135,7 @@ unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
match process::sleep(duration) {
Ok(()) => 0,
Err(remaining) => {
error::errno = errno::EINTR;
error::errno = Errno::EINTR;
remaining.as_secs() as c_uint + (remaining.subsec_nanos() != 0) as c_uint
}
}
@ -141,6 +144,6 @@ unsafe extern "C" fn sleep(seconds: c_uint) -> c_uint {
#[no_mangle]
unsafe extern "C" fn usleep(millis: c_uint) -> CIntZeroResult {
let duration = Duration::from_millis(millis.try_into().unwrap());
process::sleep(duration).e_map_err(|_| errno::EINTR)?;
process::sleep(duration).e_map_err(|_| Errno::EINTR)?;
CIntZeroResult::SUCCESS
}

View File

@ -1,6 +1,6 @@
use core::{ffi::c_char, ptr::NonNull, slice, str};
use crate::{error::EResult, headers::errno, types::wchar_t};
use crate::{error::EResult, headers::errno::Errno, types::wchar_t};
use super::mbstate_t;
@ -40,11 +40,11 @@ pub unsafe fn mbrtowc(
let size = utf8_char_width(src.cast::<u8>().read());
// TODO EILSEQ
if size > n || size == 0 {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
let slice = slice::from_raw_parts(src.cast::<u8>().as_ptr(), size);
let Ok(decoded) = str::from_utf8(slice) else {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
};
let result = decoded.chars().next().unwrap() as wchar_t;

View File

@ -7,7 +7,7 @@ use yggdrasil_rt::{
sys as syscall,
};
use crate::{error::EResult, headers::errno};
use crate::{error::EResult, headers::errno::Errno};
use super::{AsRawFd, FromRawFd};
@ -34,7 +34,7 @@ impl DirReader {
unsafe { syscall::close(fd) }?;
EResult::Ok(())
} else {
EResult::Err(errno::EBADF)
EResult::Err(Errno::EBADF)
}
}
@ -44,7 +44,7 @@ impl DirReader {
fn fill_buf(&mut self) -> EResult<&[DirectoryEntry]> {
let Some(fd) = self.fd else {
return EResult::Err(errno::EBADF);
return EResult::Err(Errno::EBADF);
};
if self.position == self.len {

View File

@ -18,8 +18,7 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, TryFromExt},
headers::{
errno,
stdio::{BUFSIZ, UNGETC_MAX, _IOFBF, _IOLBF, _IONBF},
errno::Errno, stdio::{BUFSIZ, UNGETC_MAX, _IOFBF, _IOLBF, _IONBF}
},
};
@ -315,7 +314,7 @@ impl FILE {
pub unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> EResult<usize> {
if !self.flags.contains(FileFlags::READ) {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EBADF);
return EResult::Err(Errno::EBADF);
}
self.set_direction(Direction::Read)?;
@ -351,7 +350,7 @@ impl FILE {
pub unsafe fn write_unlocked(&mut self, data: &[u8]) -> EResult<usize> {
if !self.flags.contains(FileFlags::WRITE) {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EBADF);
return EResult::Err(Errno::EBADF);
}
self.set_direction(Direction::Write)?;
@ -397,7 +396,7 @@ impl FILE {
// ungetc() for write doesn't make any sense
self.set_direction(Direction::Read)?;
if self.ungetc.len() == UNGETC_MAX {
return EResult::Err(errno::ENOMEM);
return EResult::Err(Errno::ENOMEM);
}
self.ungetc.push(ch);
EResult::Ok(())
@ -413,7 +412,7 @@ impl FILE {
if self.last_operation.is_some() {
self.flags |= FileFlags::ERROR;
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
self.ungetc.clear();
@ -468,7 +467,7 @@ impl FILE {
match self.last_operation.replace(direction) {
Some(dir) if dir != direction => {
self.flags |= FileFlags::ERROR;
EResult::Err(errno::EINVAL)
EResult::Err(Errno::EINVAL)
}
_ => EResult::Ok(()),
}
@ -561,7 +560,7 @@ impl TryFromExt<c_int> for BufferingMode {
_IOFBF => EResult::Ok(Self::Full),
_IOLBF => EResult::Ok(Self::Line),
_IONBF => EResult::Ok(Self::None),
_ => EResult::Err(errno::EINVAL),
_ => EResult::Err(Errno::EINVAL),
}
}
}

View File

@ -8,9 +8,7 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, TryFromExt},
headers::{
errno,
stdio::{SEEK_CUR, SEEK_END, SEEK_SET},
sys_types::off_t,
errno::Errno, stdio::{SEEK_CUR, SEEK_END, SEEK_SET}, sys_types::off_t
},
};
@ -31,7 +29,7 @@ pub trait Write {
match self.write(data) {
EResult::Ok(0) => todo!(),
EResult::Ok(n) => pos += n,
EResult::Err(err) if err == errno::EINTR => todo!(),
EResult::Err(Errno::EINTR) => todo!(),
EResult::Err(err) => return (pos, EResult::Err(err)),
}
}
@ -89,7 +87,7 @@ impl TryFromExt<c_int> for RawFd {
fn e_try_from(value: c_int) -> EResult<Self> {
match value {
0.. => EResult::Ok(unsafe { Self::from_raw(value as _) }),
_ => EResult::Err(errno::EBADF),
_ => EResult::Err(Errno::EBADF),
}
}
}
@ -100,13 +98,13 @@ impl TryFromExt<(off_t, c_int)> for SeekFrom {
match whence {
SEEK_SET => {
if offset < 0 {
return EResult::Err(errno::EINVAL);
return EResult::Err(Errno::EINVAL);
}
EResult::Ok(Self::Start(offset as _))
}
SEEK_CUR => EResult::Ok(Self::Current(offset)),
SEEK_END => EResult::Ok(Self::End(offset)),
_ => EResult::Err(errno::EINVAL),
_ => EResult::Err(Errno::EINVAL),
}
}
}

View File

@ -12,8 +12,7 @@ use yggdrasil_rt::{
use crate::{
error::{EResult, OptionExt},
headers::{
errno,
sys_types::{pthread_attr_t, pthread_t},
errno::Errno, sys_types::{pthread_attr_t, pthread_t}
},
};
@ -49,6 +48,7 @@ impl Thread {
let info = ThreadCreateInfo {
signal_stack: rt::ThreadSignalStack::Allocate(DEFAULT_SIGNAL_STACK_SIZE),
stack,
#[allow(clippy::redundant_closure)]
entry: rt::ThreadFunction::Closure(Box::new(move |arg| entry(arg))),
tls_image: tls::TLS_IMAGE.get().as_ref(),
};
@ -59,7 +59,7 @@ impl Thread {
}
pub fn join(id: pthread_t) -> EResult<*mut c_void> {
let thread = THREADS.lock().remove(&id).e_ok_or(errno::EINVAL)?;
let thread = THREADS.lock().remove(&id).e_ok_or(Errno::EINVAL)?;
// TODO handle EINTR during join
let result = thread.handle.join_uninterruptible().unwrap_or(null_mut());
EResult::Ok(result)

View File

@ -1,12 +1,15 @@
use core::{
ffi::{c_char, c_int, CStr}, fmt, panic::Location, ptr::NonNull
ffi::{c_char, c_int, CStr},
fmt,
panic::Location,
ptr::NonNull,
};
use yggdrasil_rt::io::RawFd;
use crate::{
error::{EResult, TryFromExt},
headers::{errno, fcntl::AT_FDCWD},
headers::{errno::Errno, fcntl::AT_FDCWD},
};
pub trait PointerExt {
@ -124,7 +127,7 @@ pub fn at_fd(fd: c_int) -> EResult<Option<RawFd>> {
match fd {
AT_FDCWD => EResult::Ok(None),
0.. => RawFd::e_try_from(fd).map(Some),
_ => EResult::Err(errno::EBADF),
_ => EResult::Err(Errno::EBADF),
}
}
@ -143,7 +146,5 @@ pub unsafe fn cstr_prefix<F: Fn(u8, u8) -> bool>(a: NonNull<u8>, b: &[u8], cmp:
// }
pub unsafe fn cstr_matches_insensitive(a: NonNull<u8>, b: &[u8]) -> bool {
cstr_prefix(a, b, |a, b| {
u8::eq_ignore_ascii_case(&a, &b)
})
cstr_prefix(a, b, |a, b| u8::eq_ignore_ascii_case(&a, &b))
}