libc: extend GNU library/tool compatibility

This commit is contained in:
Mark Poliakov 2025-03-08 22:31:50 +02:00
parent 87ae150dc1
commit fc9018585b
19 changed files with 203 additions and 45 deletions

View File

@ -1,3 +1,9 @@
#if defined(_ASSERT_H)
#undef _ASSERT_H
#undef assert
#undef __ASSERT_VOID_CAST
#endif
#ifndef _ASSERT_H #ifndef _ASSERT_H
#define _ASSERT_H 1 #define _ASSERT_H 1

View File

@ -6,6 +6,8 @@ extern "C" {
#endif #endif
extern _Thread_local int errno; extern _Thread_local int errno;
extern char *program_invocation_short_name;
extern char *program_invocation_name;
#if defined(__cplusplus) #if defined(__cplusplus)
} }

View File

@ -80,6 +80,12 @@ pub enum Errno {
// Custom errnos // Custom errnos
ENOTSUPP = 66, ENOTSUPP = 66,
ETIMEOUT = 67, ETIMEOUT = 67,
EILSEQ = 68,
EOVERFLOW = 69,
ENOTSUP = 70,
ELAST = 71,
} }
static UNKNOWN_ERROR: &CStr = static_cstr!("Unknown error"); static UNKNOWN_ERROR: &CStr = static_cstr!("Unknown error");
@ -153,6 +159,9 @@ static ERRNO_STRINGS: &[&CStr] = &[
// Custom errnos // Custom errnos
static_cstr!("Operation not supported"), static_cstr!("Operation not supported"),
static_cstr!("Operation timed out"), static_cstr!("Operation timed out"),
// GNU errnos
static_cstr!("Invalid sequence"),
static_cstr!("Integer overflow"),
]; ];
impl Errno { impl Errno {

View File

@ -93,8 +93,8 @@ enum OpenMode {
fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> { fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> {
if opts & O_DIRECTORY != 0 { if opts & O_DIRECTORY != 0 {
if opts & !O_DIRECTORY != 0 { if opts & !(O_DIRECTORY | O_SEARCH) != 0 {
todo!(); todo!("***open(O_DIRECTORY | {:#x})", opts & !O_DIRECTORY);
} }
return EResult::Ok(OpenMode::Directory); return EResult::Ok(OpenMode::Directory);
@ -126,10 +126,16 @@ fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> {
if opts & O_TRUNC != 0 { if opts & O_TRUNC != 0 {
res |= OpenOptions::TRUNCATE; res |= OpenOptions::TRUNCATE;
} }
if opts & O_NONBLOCK != 0 {
// TODO O_NONBLOCK
}
if opts & O_NOCTTY != 0 {
// TODO O_NOCTTY
}
// TODO O_CLOEXEC // TODO O_CLOEXEC
if opts & (O_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NONBLOCK | O_NOFOLLOW | O_NOCTTY) != 0 { if opts & (O_DSYNC | O_RSYNC | O_SYNC | O_TTY_INIT | O_NOFOLLOW) != 0 {
todo!(); todo!("Unhandled options: {:#x}", opts);
} }
let mode = if need_mode { 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)? { let fd = match open_opts(opts, &mut ap)? {
OpenMode::File(opts, mode) => RawFile::open_at(atfd, pathname, opts, mode)?.into_raw_fd(), 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) CFdResult::success(fd)

View File

@ -133,6 +133,7 @@ pub mod sys_statvfs;
pub mod sys_time; pub mod sys_time;
pub mod sys_times; pub mod sys_times;
pub mod sys_types; pub mod sys_types;
pub mod sys_uio;
pub mod sys_utsname; pub mod sys_utsname;
pub mod sys_wait; pub mod sys_wait;

View File

@ -22,12 +22,14 @@ pub type sig_handler_t = unsafe extern "C" fn(c_int);
pub type sigset_t = u64; pub type sigset_t = u64;
#[repr(C)] #[repr(C)]
pub struct stack_t { pub struct __stack {
pub ss_sp: *mut c_void, pub ss_sp: *mut c_void,
pub ss_flags: c_int, pub ss_flags: c_int,
pub ss_size: usize, pub ss_size: usize,
} }
pub type stack_t = __stack;
#[repr(C)] #[repr(C)]
pub struct sigevent { pub struct sigevent {
pub sigev_notify: c_int, pub sigev_notify: c_int,
@ -305,8 +307,17 @@ unsafe extern "C" fn siginterrupt(_signum: c_int, _b: c_int) -> c_int {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn sigismember(_mask: *const sigset_t, _signum: c_int) -> c_int { unsafe extern "C" fn sigismember(mask: *const sigset_t, signum: c_int) -> c_int {
todo!() 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] #[no_mangle]

View File

@ -243,3 +243,29 @@ unsafe extern "C" fn setvbuf(
fp.setvbuf(mode, buffer, size)?; fp.setvbuf(mode, buffer, size)?;
CIntZeroResult::SUCCESS 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()")
}

View File

@ -142,7 +142,7 @@ fn printf_inner<W: FmtWriter>(output: &mut W, format: &[u8], mut ap: VaList) ->
b'L' => todo!(), b'L' => todo!(),
b'j' => todo!(), b'j' => todo!(),
b'z' | b'Z' => opts.size = FmtSize::Size, b'z' | b'Z' => opts.size = FmtSize::Size,
b't' => todo!(), b't' => opts.size = FmtSize::Size,
_ => break, _ => break,
} }
cur = fmt.next(); cur = fmt.next();
@ -173,7 +173,11 @@ fn printf_inner<W: FmtWriter>(output: &mut W, format: &[u8], mut ap: VaList) ->
spec = Some(FmtSpec::String); spec = Some(FmtSpec::String);
} }
b'p' => spec = Some(FmtSpec::Pointer), 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'm' => todo!(),
b'%' => { b'%' => {
count += output.write(b"%")?; count += output.write(b"%")?;

View File

@ -2,7 +2,8 @@ language = "C"
style = "Tag" style = "Tag"
sys_includes = [ sys_includes = [
"sys/types.h" "sys/types.h",
"sys/uio.h"
] ]
no_includes = true no_includes = true

View File

@ -5,7 +5,10 @@ use core::{
use crate::{error::EResult, headers::errno::Errno, util::PointerExt}; 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 io;
mod option; mod option;
@ -31,19 +34,12 @@ pub struct sockaddr {
// TODO struct sockaddr_storage // 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)] #[derive(Clone, Copy, Debug)]
#[repr(C)] #[repr(C)]
pub struct msghdr { pub struct msghdr {
pub msg_name: *mut c_void, pub msg_name: *mut c_void,
pub msg_namelen: socklen_t, pub msg_namelen: socklen_t,
pub msg_iov: *mut iovec, pub msg_iov: *mut __ygg_iovec_t,
pub msg_iovlen: c_int, pub msg_iovlen: c_int,
pub msg_control: *mut c_void, pub msg_control: *mut c_void,
pub msg_controllen: socklen_t, pub msg_controllen: socklen_t,

View File

@ -1,12 +1,15 @@
use core::{ use core::{
ffi::{c_char, c_int}, 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::{ use crate::{
error::{CIntZeroResult, TryFromExt}, error::{CIntZeroResult, ResultExt, TryFromExt},
headers::errno::Errno,
io, io,
util::{self, PointerStrExt}, util::{self, PointerStrExt},
}; };
@ -104,23 +107,32 @@ impl From<FileAttr> for stat {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn chmod(_pathname: *const c_char, _mode: mode_t) -> c_int { unsafe extern "C" fn chmod(pathname: *const c_char, mode: mode_t) -> CIntZeroResult {
todo!() fchmodat(AT_FDCWD, pathname, mode, 0)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fchmod(_fd: c_int, _mode: mode_t) -> c_int { unsafe extern "C" fn fchmod(fd: c_int, mode: mode_t) -> CIntZeroResult {
todo!() fchmodat(fd, null(), mode, 0)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fchmodat( unsafe extern "C" fn fchmodat(
_fd: c_int, fd: c_int,
_pathname: *const c_char, pathname: *const c_char,
_mode: mode_t, mode: mode_t,
_opt: c_int, _opt: c_int,
) -> c_int { ) -> CIntZeroResult {
todo!() 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] #[no_mangle]
@ -222,7 +234,8 @@ unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> CIntZe
#[no_mangle] #[no_mangle]
unsafe extern "C" fn futimens(_fd: c_int, _times: *const __ygg_timespec_t) -> c_int { unsafe extern "C" fn futimens(_fd: c_int, _times: *const __ygg_timespec_t) -> c_int {
todo!() log::warn!("TODO: futimens");
0
} }
#[no_mangle] #[no_mangle]

View File

@ -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"]

View File

@ -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!()
}

View File

@ -27,6 +27,11 @@ unsafe extern "C" fn execp(file: *const c_char, argv: *const *mut c_char) -> c_i
todo!() todo!()
} }
#[no_mangle]
unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int {
todo!()
}
#[no_mangle] #[no_mangle]
unsafe extern "C" fn execve( unsafe extern "C" fn execve(
file: *const c_char, file: *const c_char,

View File

@ -3,15 +3,17 @@ use core::{
ptr::{null_mut, NonNull}, ptr::{null_mut, NonNull},
}; };
use yggdrasil_rt::io::RemoveFlags;
use crate::{ use crate::{
error::{self, CIntZeroResult, CPtrResult, EResult, TryFromExt}, error::{self, CIntZeroResult, CPtrResult, EResult, ResultExt, TryFromExt},
headers::{ headers::{
errno::Errno, errno::Errno,
fcntl::{faccessat, AT_FDCWD}, fcntl::{faccessat, AT_FDCWD, AT_REMOVEDIR},
sys_types::{gid_t, off_t, uid_t}, sys_types::{gid_t, off_t, uid_t},
}, },
io::{self, raw::RawFile, FromRawFd}, io::{self, raw::RawFile, FromRawFd},
util::{PointerExt, PointerStrExt}, util::{self, PointerExt, PointerStrExt},
}; };
pub const _PC_PATH_MAX: c_int = 0; pub const _PC_PATH_MAX: c_int = 0;
@ -40,7 +42,8 @@ unsafe extern "C" fn fchdir(fd: c_int) -> c_int {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fchown(fd: c_int, uid: uid_t, gid: gid_t) -> c_int { 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] #[no_mangle]
@ -135,12 +138,17 @@ unsafe extern "C" fn truncate(path: *const c_char, size: off_t) -> c_int {
todo!() todo!()
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn unlink(path: *const c_char) -> c_int { unsafe extern "C" fn unlink(path: *const c_char) -> CIntZeroResult {
let path = path.ensure_str(); unlinkat(AT_FDCWD, path, 0)
log::warn!("TODO: unlink({path:?})");
0
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn unlinkat(atfd: c_int, path: *const c_char, flags: c_int) -> c_int { unsafe extern "C" fn unlinkat(atfd: c_int, path: *const c_char, flags: c_int) -> CIntZeroResult {
todo!() 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
} }

View File

@ -294,6 +294,13 @@ impl FILE {
self.lock.release(); 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) { // pub fn reset(&mut self) {
// if let Some(read_buffer) = self.read_buffer.as_mut() { // if let Some(read_buffer) = self.read_buffer.as_mut() {
// read_buffer.reset(); // read_buffer.reset();

View File

@ -24,6 +24,11 @@ impl RawFile {
EResult::Ok(Self(fd)) EResult::Ok(Self(fd))
} }
pub fn open_directory_at<P: AsRef<Path>>(at: Option<RawFd>, pathname: P) -> EResult<Self> {
let fd = unsafe { syscall::open_directory(at, pathname.as_ref().as_str()) }?;
EResult::Ok(Self(fd))
}
pub unsafe fn close(&mut self) -> EResult<()> { pub unsafe fn close(&mut self) -> EResult<()> {
unsafe { syscall::close(self.0) }?; unsafe { syscall::close(self.0) }?;
EResult::Ok(()) EResult::Ok(())

View File

@ -1,6 +1,7 @@
use core::{ use core::{
ffi::{c_char, c_int, c_void, CStr}, ffi::{c_char, c_int, c_void, CStr},
mem::MaybeUninit, mem::MaybeUninit,
ptr::null_mut,
time::Duration, 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<Vec<extern "C" fn()>> = Mutex::new(Vec::new()); static AT_EXIT: Mutex<Vec<extern "C" fn()>> = Mutex::new(Vec::new());
// TODO this will be in the linker instead // TODO this will be in the linker instead
static AT_DSO_EXIT: Mutex<Vec<DsoDestructor>> = Mutex::new(Vec::new()); static AT_DSO_EXIT: Mutex<Vec<DsoDestructor>> = Mutex::new(Vec::new());

View File

@ -85,6 +85,19 @@ impl Node for Port {
} }
impl NormalPort { impl NormalPort {
fn default_c_dependencies(name: &str) -> Vec<String> {
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<Self, PortError> { pub fn load(env: &BuildEnv, name: &str) -> Result<Self, PortError> {
let manifest_dir = env.workspace_root.join("ports").join(name); let manifest_dir = env.workspace_root.join("ports").join(name);
let source_dir = env let source_dir = env
@ -108,7 +121,7 @@ impl NormalPort {
Some(deps) => { Some(deps) => {
let mut d = vec![]; let mut d = vec![];
if deps.c_compiler.unwrap_or(true) { 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() { if let Some(build) = deps.build.as_ref() {
d.extend(build.iter().cloned()); d.extend(build.iter().cloned());
@ -118,7 +131,7 @@ impl NormalPort {
} }
d d
} }
None => vec!["meta-llvm".into()], None => Self::default_c_dependencies(name),
}; };
Ok(Self { Ok(Self {