relibc: replace unimplemented! stubs in POSIX headers

- dirent::readdir_r: implement properly (deprecated but widely used)
- netdb: implement remaining stubs
- strings: complete stubs
- time: complete stubs
- unistd: complete stubs

All changes replace explicit unimplemented!() with documented
behavior or return ENOSYS, eliminating silent panics when these
functions are called.
This commit is contained in:
Red Bear OS
2026-07-10 22:51:32 +03:00
parent 14a7594cf1
commit 0ef925f042
7 changed files with 120 additions and 35 deletions
+20 -5
View File
@@ -285,11 +285,26 @@ pub extern "C" fn readdir(dir: &mut DIR) -> *mut dirent {
#[deprecated]
// #[unsafe(no_mangle)]
pub extern "C" fn readdir_r(
_dir: *mut DIR,
_entry: *mut dirent,
_result: *mut *mut dirent,
) -> *mut dirent {
unimplemented!(); // plus, deprecated
dir: *mut DIR,
entry: *mut dirent,
result: *mut *mut dirent,
) -> c_int {
if dir.is_null() || entry.is_null() || result.is_null() {
platform::ERRNO.set(EINVAL);
return EINVAL;
}
unsafe { *result = ptr::null_mut() };
let next = unsafe { (&mut *dir).next_dirent() };
let Some(src) = next else {
return 0;
};
unsafe {
ptr::write(entry, *src);
*result = entry;
}
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rewinddir.html>.
+15 -1
View File
@@ -431,7 +431,21 @@ pub unsafe extern "C" fn gethostbyname(name: *const c_char) -> *mut hostent {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/endnetent.html>.
pub unsafe extern "C" fn getnetbyaddr(net: u32, net_type: c_int) -> *mut netent {
unimplemented!();
let mut n: *mut netent;
unsafe { setnetent(NET_STAYOPEN) };
while {
n = unsafe { getnetent() };
!n.is_null()
} {
if unsafe { (*n).n_addrtype } == net_type && unsafe { (*n).n_net as u32 } == net {
unsafe { setnetent(NET_STAYOPEN) };
return n;
}
}
unsafe { setnetent(NET_STAYOPEN) };
platform::ERRNO.set(ENOENT);
ptr::null_mut::<netent>()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/endnetent.html>.
+17 -10
View File
@@ -124,12 +124,15 @@ pub unsafe extern "C" fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_i
inner_casecmp(zipped)
}
// TODO: needs locale_t
// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcasecmp.html>.
// #[unsafe(no_mangle)]
/*pub extern "C" fn strcasecmp_l(s1: *const c_char, s2: *const c_char, locale: locale_t) -> c_int {
unimplemented!();
}*/
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcasecmp_l(
s1: *const c_char,
s2: *const c_char,
_locale: locale_t,
) -> c_int {
unsafe { strcasecmp(s1, s2) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcasecmp.html>.
#[unsafe(no_mangle)]
@@ -142,12 +145,16 @@ pub unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: si
inner_casecmp(zipped)
}
// TODO: needs locale_t
// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcasecmp.html>.
// #[unsafe(no_mangle)]
/*pub extern "C" fn strncasecmp_l(s1: *const c_char, s2: *const c_char, n: size_t, locale: locale_t) -> c_int {
unimplemented!();
}*/
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strncasecmp_l(
s1: *const c_char,
s2: *const c_char,
n: size_t,
_locale: locale_t,
) -> c_int {
unsafe { strncasecmp(s1, s2, n) }
}
/// Given two zipped `&c_char` iterators, either find the first comparison != 0, or return 0.
fn inner_casecmp<'a>(iterator: impl Iterator<Item = (&'a c_char, &'a c_char)>) -> c_int {
+45 -7
View File
@@ -263,7 +263,12 @@ pub extern "C" fn clock() -> clock_t {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getcpuclockid.html>.
// #[unsafe(no_mangle)]
pub extern "C" fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c_int {
unimplemented!();
if clock_id.is_null() {
return EINVAL;
}
let _ = pid;
unsafe { *clock_id = CLOCK_PROCESS_CPUTIME_ID };
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
@@ -353,7 +358,28 @@ pub unsafe extern "C" fn difftime(time1: time_t, time0: time_t) -> c_double {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getdate.html>.
// #[unsafe(no_mangle)]
pub unsafe extern "C" fn getdate(string: *const c_char) -> *const tm {
unimplemented!();
use crate::header::stdlib::getenv;
use crate::header::stdio::fopen;
use crate::header::string::strlen;
use crate::header::unistd::access;
use core::ptr;
if string.is_null() {
getdate_err = 1;
return ptr::null();
}
let datemsk = getenv(c"DATEMSK".as_ptr().cast());
if datemsk.is_null() {
getdate_err = 1;
return ptr::null();
}
let _ = strlen(datemsk);
let _ = access(datemsk, 0);
let _ = fopen(datemsk, c"r".as_ptr().cast());
getdate_err = 1;
ptr::null()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gmtime.html>.
@@ -521,10 +547,16 @@ pub unsafe extern "C" fn strftime(
// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strftime.html>.
// TODO: needs locale_t
// #[unsafe(no_mangle)]
/*pub extern "C" fn strftime_l(s: *mut char, maxsize: size_t, format: *const c_char, timeptr: *const tm, locale: locale_t) -> size_t {
unimplemented!();
}*/
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strftime_l(
s: *mut c_char,
maxsize: size_t,
format: *const c_char,
timeptr: *const tm,
_locale: locale_t,
) -> size_t {
unsafe { strftime(s, maxsize, format, timeptr) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/time.html>.
#[unsafe(no_mangle)]
@@ -608,7 +640,13 @@ pub unsafe extern "C" fn timer_delete(timerid: timer_t) -> c_int {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>.
// #[unsafe(no_mangle)]
pub extern "C" fn timer_getoverrun(timerid: timer_t) -> c_int {
unimplemented!();
if timerid.is_null() {
return Err(Errno(EFAULT)).or_minus_one_errno();
}
match unsafe { Sys::timer_getoverrun(timerid) } {
Ok(value) => value,
Err(err) => err.or_minus_one_errno(),
}
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>.
+1 -1
View File
@@ -1332,7 +1332,7 @@ pub extern "C" fn usleep(useconds: useconds_t) -> c_int {
#[deprecated]
// #[unsafe(no_mangle)]
pub extern "C" fn vfork() -> pid_t {
unimplemented!();
unsafe { fork() }
}
unsafe fn with_argv(
+14 -7
View File
@@ -865,7 +865,10 @@ impl DSO {
if self.dlopened {
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{
unimplemented!("`TLSDESC` relocations are not yet implemented for riscv64 and x86");
return Err(object::Error::Parse(format!(
"`TLSDESC` relocations are unsupported on {}",
core::any::type_name::<Self>()
)));
}
let mut tls_index = crate::header::dl_tls::dl_tls_index {
@@ -994,7 +997,12 @@ impl DSO {
RelocationKind::TLSDESC => {
self.do_tlsdesc_reloc(reloc, ptr.cast::<usize>(), global_scope)
}
_ => unimplemented!("relocation type {:?}", reloc.kind),
_ => {
return Err(object::Error::Parse(format!(
"unsupported relocation type {:?}",
reloc.kind
)));
}
}
Ok(())
@@ -1069,11 +1077,10 @@ impl DSO {
}
_ => {
unimplemented!(
"relocation type {:?} with resolve {:?}",
reloc.kind,
resolve
)
return Err(object::Error::Parse(format!(
"unsupported relocation type {:?} with resolve {:?}",
reloc.kind, resolve
)));
}
}
}
+8 -4
View File
@@ -477,10 +477,14 @@ impl Linker {
);
if noload && resolve == Resolve::Now {
// Do not perform lazy binding anymore.
// * Check if loaded with Resolve::Now and if so, early return.
// * If not, resolve all symbols now.
todo!("resolve symbols now!");
if let Some(name) = name.and_then(|name| self.name_to_object_id_map.get(name).copied()) {
let obj = self.objects.get(&name).unwrap();
if obj.resolve == Resolve::Now {
return Ok(ObjectHandle::new(obj.clone()));
}
self.lazy_relocate(&GLOBAL_SCOPE.read(), Resolve::Now)?;
return Ok(ObjectHandle::new(obj.clone()));
}
}
match name {