diff --git a/userspace/lib/ygglibc/include/assert.h b/userspace/lib/ygglibc/include/assert.h index 5c3df984..857b6329 100644 --- a/userspace/lib/ygglibc/include/assert.h +++ b/userspace/lib/ygglibc/include/assert.h @@ -1,3 +1,9 @@ +#if defined(_ASSERT_H) +#undef _ASSERT_H +#undef assert +#undef __ASSERT_VOID_CAST +#endif + #ifndef _ASSERT_H #define _ASSERT_H 1 diff --git a/userspace/lib/ygglibc/include/bits/errno.h b/userspace/lib/ygglibc/include/bits/errno.h index f71b69d9..04889270 100644 --- a/userspace/lib/ygglibc/include/bits/errno.h +++ b/userspace/lib/ygglibc/include/bits/errno.h @@ -6,6 +6,8 @@ extern "C" { #endif extern _Thread_local int errno; +extern char *program_invocation_short_name; +extern char *program_invocation_name; #if defined(__cplusplus) } diff --git a/userspace/lib/ygglibc/src/headers/errno/mod.rs b/userspace/lib/ygglibc/src/headers/errno/mod.rs index f021c725..4cad1ca9 100644 --- a/userspace/lib/ygglibc/src/headers/errno/mod.rs +++ b/userspace/lib/ygglibc/src/headers/errno/mod.rs @@ -80,6 +80,12 @@ pub enum Errno { // Custom errnos ENOTSUPP = 66, ETIMEOUT = 67, + + EILSEQ = 68, + EOVERFLOW = 69, + ENOTSUP = 70, + + ELAST = 71, } static UNKNOWN_ERROR: &CStr = static_cstr!("Unknown error"); @@ -153,6 +159,9 @@ static ERRNO_STRINGS: &[&CStr] = &[ // Custom errnos static_cstr!("Operation not supported"), static_cstr!("Operation timed out"), + // GNU errnos + static_cstr!("Invalid sequence"), + static_cstr!("Integer overflow"), ]; impl Errno { diff --git a/userspace/lib/ygglibc/src/headers/fcntl/mod.rs b/userspace/lib/ygglibc/src/headers/fcntl/mod.rs index 49b8bc3f..d127c5c1 100644 --- a/userspace/lib/ygglibc/src/headers/fcntl/mod.rs +++ b/userspace/lib/ygglibc/src/headers/fcntl/mod.rs @@ -93,8 +93,8 @@ enum OpenMode { fn open_opts(opts: c_int, ap: &mut VaList) -> EResult { if opts & O_DIRECTORY != 0 { - if opts & !O_DIRECTORY != 0 { - todo!(); + if opts & !(O_DIRECTORY | O_SEARCH) != 0 { + todo!("***open(O_DIRECTORY | {:#x})", opts & !O_DIRECTORY); } return EResult::Ok(OpenMode::Directory); @@ -126,10 +126,16 @@ fn open_opts(opts: c_int, ap: &mut VaList) -> EResult { if opts & O_TRUNC != 0 { res |= OpenOptions::TRUNCATE; } + if opts & O_NONBLOCK != 0 { + // TODO O_NONBLOCK + } + if opts & O_NOCTTY != 0 { + // TODO O_NOCTTY + } // TODO O_CLOEXEC - if opts & (O_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NONBLOCK | O_NOFOLLOW | O_NOCTTY) != 0 { - todo!(); + if opts & (O_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NOFOLLOW) != 0 { + todo!("Unhandled options: {:#x}", opts); } let mode = if need_mode { @@ -162,7 +168,7 @@ unsafe fn vopenat(atfd: c_int, pathname: *const c_char, opts: c_int, mut ap: VaL let fd = match open_opts(opts, &mut ap)? { OpenMode::File(opts, mode) => RawFile::open_at(atfd, pathname, opts, mode)?.into_raw_fd(), - OpenMode::Directory => todo!(), + OpenMode::Directory => RawFile::open_directory_at(atfd, pathname)?.into_raw_fd(), }; CFdResult::success(fd) diff --git a/userspace/lib/ygglibc/src/headers/mod.rs b/userspace/lib/ygglibc/src/headers/mod.rs index 5ecb3fc8..256c1b5a 100644 --- a/userspace/lib/ygglibc/src/headers/mod.rs +++ b/userspace/lib/ygglibc/src/headers/mod.rs @@ -133,6 +133,7 @@ pub mod sys_statvfs; pub mod sys_time; pub mod sys_times; pub mod sys_types; +pub mod sys_uio; pub mod sys_utsname; pub mod sys_wait; diff --git a/userspace/lib/ygglibc/src/headers/signal/mod.rs b/userspace/lib/ygglibc/src/headers/signal/mod.rs index 4af1017c..e34fe9a7 100644 --- a/userspace/lib/ygglibc/src/headers/signal/mod.rs +++ b/userspace/lib/ygglibc/src/headers/signal/mod.rs @@ -22,12 +22,14 @@ pub type sig_handler_t = unsafe extern "C" fn(c_int); pub type sigset_t = u64; #[repr(C)] -pub struct stack_t { +pub struct __stack { pub ss_sp: *mut c_void, pub ss_flags: c_int, pub ss_size: usize, } +pub type stack_t = __stack; + #[repr(C)] pub struct sigevent { pub sigev_notify: c_int, @@ -305,8 +307,17 @@ unsafe extern "C" fn siginterrupt(_signum: c_int, _b: c_int) -> c_int { } #[no_mangle] -unsafe extern "C" fn sigismember(_mask: *const sigset_t, _signum: c_int) -> c_int { - todo!() +unsafe extern "C" fn sigismember(mask: *const sigset_t, signum: c_int) -> c_int { + if signum > 63 || signum <= 0 { + error::errno = Errno::EINVAL; + return -1; + } + let mask = *mask.ensure(); + if mask & (1 << signum) != 0 { + 1 + } else { + 0 + } } #[no_mangle] diff --git a/userspace/lib/ygglibc/src/headers/stdio/file.rs b/userspace/lib/ygglibc/src/headers/stdio/file.rs index 320c5819..c7531b7f 100644 --- a/userspace/lib/ygglibc/src/headers/stdio/file.rs +++ b/userspace/lib/ygglibc/src/headers/stdio/file.rs @@ -243,3 +243,29 @@ unsafe extern "C" fn setvbuf( fp.setvbuf(mode, buffer, size)?; CIntZeroResult::SUCCESS } + +#[no_mangle] +unsafe extern "C" fn fpurge(_fp: *mut FILE) { + todo!("fpurge()") +} + +#[no_mangle] +unsafe extern "C" fn __fpurge(_fp: *mut FILE) { + todo!("__fpurge()") +} + +#[no_mangle] +unsafe extern "C" fn freading(fp: *mut FILE) -> c_int { + __freading(fp) +} + +#[no_mangle] +unsafe extern "C" fn __freading(fp: *mut FILE) -> c_int { + let fp = fp.ensure_mut(); + fp.reading() as c_int +} + +#[no_mangle] +unsafe extern "C" fn __fseterr(_fp: *mut FILE) { + todo!("__fseterr()") +} diff --git a/userspace/lib/ygglibc/src/headers/stdio/printf/mod.rs b/userspace/lib/ygglibc/src/headers/stdio/printf/mod.rs index fb937221..0088887a 100644 --- a/userspace/lib/ygglibc/src/headers/stdio/printf/mod.rs +++ b/userspace/lib/ygglibc/src/headers/stdio/printf/mod.rs @@ -142,7 +142,7 @@ fn printf_inner(output: &mut W, format: &[u8], mut ap: VaList) -> b'L' => todo!(), b'j' => todo!(), b'z' | b'Z' => opts.size = FmtSize::Size, - b't' => todo!(), + b't' => opts.size = FmtSize::Size, _ => break, } cur = fmt.next(); @@ -173,7 +173,11 @@ fn printf_inner(output: &mut W, format: &[u8], mut ap: VaList) -> spec = Some(FmtSpec::String); } b'p' => spec = Some(FmtSpec::Pointer), - b'n' => todo!(), + b'n' => unsafe { + let arg = ap.arg::<*mut c_int>(); + *arg = count as c_int; + continue; + }, b'm' => todo!(), b'%' => { count += output.write(b"%")?; diff --git a/userspace/lib/ygglibc/src/headers/sys_socket/cbindgen.toml b/userspace/lib/ygglibc/src/headers/sys_socket/cbindgen.toml index 72a85dd8..b878ac96 100644 --- a/userspace/lib/ygglibc/src/headers/sys_socket/cbindgen.toml +++ b/userspace/lib/ygglibc/src/headers/sys_socket/cbindgen.toml @@ -2,7 +2,8 @@ language = "C" style = "Tag" sys_includes = [ - "sys/types.h" + "sys/types.h", + "sys/uio.h" ] no_includes = true diff --git a/userspace/lib/ygglibc/src/headers/sys_socket/mod.rs b/userspace/lib/ygglibc/src/headers/sys_socket/mod.rs index b373735a..3f3dce31 100644 --- a/userspace/lib/ygglibc/src/headers/sys_socket/mod.rs +++ b/userspace/lib/ygglibc/src/headers/sys_socket/mod.rs @@ -5,7 +5,10 @@ use core::{ use crate::{error::EResult, headers::errno::Errno, util::PointerExt}; -use super::netinet_in::{sockaddr_in, sockaddr_in6}; +use super::{ + netinet_in::{sockaddr_in, sockaddr_in6}, + sys_uio::__ygg_iovec_t, +}; mod io; mod option; @@ -31,19 +34,12 @@ pub struct sockaddr { // TODO struct sockaddr_storage -// TODO struct iovec from sys/uio.h -#[derive(Clone, Copy, Debug)] -#[repr(C)] -pub struct iovec { - __dummy: u32, -} - #[derive(Clone, Copy, Debug)] #[repr(C)] pub struct msghdr { pub msg_name: *mut c_void, pub msg_namelen: socklen_t, - pub msg_iov: *mut iovec, + pub msg_iov: *mut __ygg_iovec_t, pub msg_iovlen: c_int, pub msg_control: *mut c_void, pub msg_controllen: socklen_t, diff --git a/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs b/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs index 885b197d..7f1a6319 100644 --- a/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs +++ b/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs @@ -1,12 +1,15 @@ use core::{ ffi::{c_char, c_int}, - ptr::NonNull, + ptr::{null, NonNull}, }; -use yggdrasil_rt::io::{FileAttr, FileMode, FileType, RawFd}; +use yggdrasil_rt::io::{ + FileAttr, FileMetadataUpdate, FileMetadataUpdateMode, FileMode, FileType, RawFd, +}; use crate::{ - error::{CIntZeroResult, TryFromExt}, + error::{CIntZeroResult, ResultExt, TryFromExt}, + headers::errno::Errno, io, util::{self, PointerStrExt}, }; @@ -104,23 +107,32 @@ impl From for stat { } #[no_mangle] -unsafe extern "C" fn chmod(_pathname: *const c_char, _mode: mode_t) -> c_int { - todo!() +unsafe extern "C" fn chmod(pathname: *const c_char, mode: mode_t) -> CIntZeroResult { + fchmodat(AT_FDCWD, pathname, mode, 0) } #[no_mangle] -unsafe extern "C" fn fchmod(_fd: c_int, _mode: mode_t) -> c_int { - todo!() +unsafe extern "C" fn fchmod(fd: c_int, mode: mode_t) -> CIntZeroResult { + fchmodat(fd, null(), mode, 0) } #[no_mangle] unsafe extern "C" fn fchmodat( - _fd: c_int, - _pathname: *const c_char, - _mode: mode_t, + fd: c_int, + pathname: *const c_char, + mode: mode_t, _opt: c_int, -) -> c_int { - todo!() +) -> CIntZeroResult { + let atfd = util::at_fd(fd)?; + let path = if pathname.is_null() { + "" + } else { + pathname.ensure_str() + }; + let mode = unsafe { FileMode::from_raw((mode as u32) & 0o777) }; + let update = FileMetadataUpdate::Permissions(FileMetadataUpdateMode::Set(mode)); + unsafe { yggdrasil_rt::sys::update_metadata(atfd, path, &update) }.e_map_err(Errno::from)?; + CIntZeroResult::SUCCESS } #[no_mangle] @@ -222,7 +234,8 @@ unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> CIntZe #[no_mangle] unsafe extern "C" fn futimens(_fd: c_int, _times: *const __ygg_timespec_t) -> c_int { - todo!() + log::warn!("TODO: futimens"); + 0 } #[no_mangle] diff --git a/userspace/lib/ygglibc/src/headers/sys_uio/cbindgen.toml b/userspace/lib/ygglibc/src/headers/sys_uio/cbindgen.toml new file mode 100644 index 00000000..88baae53 --- /dev/null +++ b/userspace/lib/ygglibc/src/headers/sys_uio/cbindgen.toml @@ -0,0 +1,17 @@ +language = "C" +style = "Tag" + +sys_includes = [ + "stddef.h", + "stdint.h", + "sys/types.h", +] +no_includes = true + +include_guard = "_SYS_UIO_H" + +usize_type = "size_t" +isize_type = "ssize_t" + +[export] +include = ["iovec", "__ygg_iovec_t"] diff --git a/userspace/lib/ygglibc/src/headers/sys_uio/mod.rs b/userspace/lib/ygglibc/src/headers/sys_uio/mod.rs new file mode 100644 index 00000000..86a753af --- /dev/null +++ b/userspace/lib/ygglibc/src/headers/sys_uio/mod.rs @@ -0,0 +1,20 @@ +use core::ffi::{c_int, c_void}; + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct iovec { + pub iov_base: *mut c_void, + pub iov_len: usize, +} + +pub type __ygg_iovec_t = iovec; + +#[no_mangle] +unsafe extern "C" fn readv(_fd: c_int, _slice: *const iovec, _flags: c_int) -> isize { + todo!() +} + +#[no_mangle] +unsafe extern "C" fn writev(_fd: c_int, _slice: *const iovec, _flags: c_int) -> isize { + todo!() +} diff --git a/userspace/lib/ygglibc/src/headers/unistd/exec.rs b/userspace/lib/ygglibc/src/headers/unistd/exec.rs index d6e6c236..383243ff 100644 --- a/userspace/lib/ygglibc/src/headers/unistd/exec.rs +++ b/userspace/lib/ygglibc/src/headers/unistd/exec.rs @@ -27,6 +27,11 @@ unsafe extern "C" fn execp(file: *const c_char, argv: *const *mut c_char) -> c_i todo!() } +#[no_mangle] +unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int { + todo!() +} + #[no_mangle] unsafe extern "C" fn execve( file: *const c_char, diff --git a/userspace/lib/ygglibc/src/headers/unistd/fs.rs b/userspace/lib/ygglibc/src/headers/unistd/fs.rs index 4264d90c..b74aadca 100644 --- a/userspace/lib/ygglibc/src/headers/unistd/fs.rs +++ b/userspace/lib/ygglibc/src/headers/unistd/fs.rs @@ -3,15 +3,17 @@ use core::{ ptr::{null_mut, NonNull}, }; +use yggdrasil_rt::io::RemoveFlags; + use crate::{ - error::{self, CIntZeroResult, CPtrResult, EResult, TryFromExt}, + error::{self, CIntZeroResult, CPtrResult, EResult, ResultExt, TryFromExt}, headers::{ errno::Errno, - fcntl::{faccessat, AT_FDCWD}, + fcntl::{faccessat, AT_FDCWD, AT_REMOVEDIR}, sys_types::{gid_t, off_t, uid_t}, }, io::{self, raw::RawFile, FromRawFd}, - util::{PointerExt, PointerStrExt}, + util::{self, PointerExt, PointerStrExt}, }; pub const _PC_PATH_MAX: c_int = 0; @@ -40,7 +42,8 @@ unsafe extern "C" fn fchdir(fd: c_int) -> c_int { #[no_mangle] unsafe extern "C" fn fchown(fd: c_int, uid: uid_t, gid: gid_t) -> c_int { - todo!() + log::warn!("TODO: fchown({uid}, {gid})"); + 0 } #[no_mangle] @@ -135,12 +138,17 @@ unsafe extern "C" fn truncate(path: *const c_char, size: off_t) -> c_int { todo!() } #[no_mangle] -unsafe extern "C" fn unlink(path: *const c_char) -> c_int { - let path = path.ensure_str(); - log::warn!("TODO: unlink({path:?})"); - 0 +unsafe extern "C" fn unlink(path: *const c_char) -> CIntZeroResult { + unlinkat(AT_FDCWD, path, 0) } #[no_mangle] -unsafe extern "C" fn unlinkat(atfd: c_int, path: *const c_char, flags: c_int) -> c_int { - todo!() +unsafe extern "C" fn unlinkat(atfd: c_int, path: *const c_char, flags: c_int) -> CIntZeroResult { + let atfd = util::at_fd(atfd)?; + let path = path.ensure_str(); + let mut f = RemoveFlags::empty(); + if flags & AT_REMOVEDIR != 0 { + f |= RemoveFlags::DIRECTORY; + } + unsafe { yggdrasil_rt::sys::remove(atfd, path, f) }.e_map_err(Errno::from)?; + CIntZeroResult::SUCCESS } diff --git a/userspace/lib/ygglibc/src/io/managed.rs b/userspace/lib/ygglibc/src/io/managed.rs index 5d2e7624..baf29938 100644 --- a/userspace/lib/ygglibc/src/io/managed.rs +++ b/userspace/lib/ygglibc/src/io/managed.rs @@ -294,6 +294,13 @@ impl FILE { self.lock.release(); } + pub fn reading(&self) -> bool { + !self.flags.contains(FileFlags::WRITE) + || self + .last_operation + .map_or(false, |op| op == Direction::Read) + } + // pub fn reset(&mut self) { // if let Some(read_buffer) = self.read_buffer.as_mut() { // read_buffer.reset(); diff --git a/userspace/lib/ygglibc/src/io/raw.rs b/userspace/lib/ygglibc/src/io/raw.rs index cf49772d..5ef579db 100644 --- a/userspace/lib/ygglibc/src/io/raw.rs +++ b/userspace/lib/ygglibc/src/io/raw.rs @@ -24,6 +24,11 @@ impl RawFile { EResult::Ok(Self(fd)) } + pub fn open_directory_at>(at: Option, pathname: P) -> EResult { + let fd = unsafe { syscall::open_directory(at, pathname.as_ref().as_str()) }?; + EResult::Ok(Self(fd)) + } + pub unsafe fn close(&mut self) -> EResult<()> { unsafe { syscall::close(self.0) }?; EResult::Ok(()) diff --git a/userspace/lib/ygglibc/src/process.rs b/userspace/lib/ygglibc/src/process.rs index da105559..bae932db 100644 --- a/userspace/lib/ygglibc/src/process.rs +++ b/userspace/lib/ygglibc/src/process.rs @@ -1,6 +1,7 @@ use core::{ ffi::{c_char, c_int, c_void, CStr}, mem::MaybeUninit, + ptr::null_mut, time::Duration, }; @@ -29,6 +30,13 @@ impl DsoDestructor { } } +#[allow(non_upper_case_globals)] +#[no_mangle] +static mut program_invocation_short_name: *mut c_char = null_mut(); +#[allow(non_upper_case_globals)] +#[no_mangle] +static mut program_invocation_name: *mut c_char = null_mut(); + static AT_EXIT: Mutex> = Mutex::new(Vec::new()); // TODO this will be in the linker instead static AT_DSO_EXIT: Mutex> = Mutex::new(Vec::new()); diff --git a/xtask/src/build/ports.rs b/xtask/src/build/ports.rs index ac7503bb..199f1f38 100644 --- a/xtask/src/build/ports.rs +++ b/xtask/src/build/ports.rs @@ -85,6 +85,19 @@ impl Node for Port { } impl NormalPort { + fn default_c_dependencies(name: &str) -> Vec { + let mut d = vec![]; + d.push("meta-llvm".into()); + d.push("meta-libc".into()); + if name != "compiler-rt" { + d.push("compiler-rt".into()); + } + if name != "compiler-rt" && name != "openlibm" { + d.push("openlibm".into()); + } + d + } + pub fn load(env: &BuildEnv, name: &str) -> Result { let manifest_dir = env.workspace_root.join("ports").join(name); let source_dir = env @@ -108,7 +121,7 @@ impl NormalPort { Some(deps) => { let mut d = vec![]; if deps.c_compiler.unwrap_or(true) { - d.push("meta-llvm".into()); + d.extend_from_slice(&Self::default_c_dependencies(name)); } if let Some(build) = deps.build.as_ref() { d.extend(build.iter().cloned()); @@ -118,7 +131,7 @@ impl NormalPort { } d } - None => vec!["meta-llvm".into()], + None => Self::default_c_dependencies(name), }; Ok(Self {