relibc: complete round-9 fixes and repair ifaddrs compilation

Builds on a41c5cb0 (round-9 stub replacements) with three enhancements
and a critical compilation fix:

1. getrusage (platform/redox/mod.rs): Extended ProcStatFields to parse
   minflt (field 7) and majflt (field 9) from the kernel proc scheme
   stat line. These fields are present in the Linux-compatible stat
   format but currently hardwired to zero by the kernel; relibc now
   parses and forwards them so they report real values automatically
   when the kernel starts tracking them. inblock/oublock/nvcsw/nivcsw
   remain zero (not present in the proc stat line). clock_settime stub
   (todo_skip!) replaced with real syscall::syscall2(SYS_CLOCK_SETTIME).

2. pthread_condattr_setclock (pthread/cond.rs): Added
   CLOCK_PROCESS_CPUTIME_ID (value 2, defined in constants.rs) to the
   accepted clock list alongside CLOCK_REALTIME and CLOCK_MONOTONIC.
   CLOCK_THREAD_CPUTIME_ID, CLOCK_REALTIME_COARSE, and
   CLOCK_MONOTONIC_COARSE are not defined on Redox so cannot be
   accepted.

3. ifaddrs (header/ifaddrs/mod.rs): Fixed 7 pre-existing compilation
   errors that blocked the entire relibc library from compiling.
   The module was introduced in d9760bdc but never compiled: wrong
   imports (AF_INET from netinet_in instead of sys_socket, sa_family_t
   from sys_socket instead of bits_safamily_t, nonexistent AF_PACKET),
   missing Vec import, copy_nonoverlapping direction reversed (copied
   FROM zeroed sockaddr INTO source data), prefix validation inverted
   (rejected all valid 0-128 values), IPv6 address bytes never copied
   into sockaddr_in6, edition-2024 unsafe-block requirements.
This commit is contained in:
2026-07-27 10:46:57 +09:00
committed by Red Bear OS
parent a41c5cb0b7
commit 4ff980abd7
3 changed files with 90 additions and 35 deletions
+58 -26
View File
@@ -5,8 +5,9 @@
use crate::{
header::{
errno, stdlib,
netinet_in::{sockaddr_in, sockaddr_in6, AF_INET},
sys_socket::{sa_family_t, sockaddr, AF_PACKET},
bits_safamily_t::sa_family_t,
netinet_in::{sockaddr_in, sockaddr_in6},
sys_socket::{sockaddr},
},
platform::{
self,
@@ -14,6 +15,7 @@ use crate::{
},
};
use alloc::vec::Vec;
use core::ptr;
#[cfg(target_os = "redox")]
@@ -21,6 +23,9 @@ const O_RDONLY: usize = 0;
#[cfg(target_os = "redox")]
const O_DIRECTORY: usize = 0x10000;
const AF_INET: sa_family_t = 2;
const AF_INET6: sa_family_t = 10;
#[cfg(target_os = "redox")]
#[repr(C)]
struct Dirent {
@@ -94,7 +99,7 @@ pub unsafe extern "C" fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int {
let mut head: *mut ifaddrs = ptr::null_mut();
let mut tail: *mut *mut ifaddrs = &mut head;
let Ok(interfaces) = enumerate_interfaces() else {
*ifap = ptr::null_mut();
unsafe { *ifap = ptr::null_mut() };
platform::ERRNO.set(errno::ENOSYS);
return -1;
};
@@ -103,17 +108,17 @@ pub unsafe extern "C" fn getifaddrs(ifap: *mut *mut ifaddrs) -> c_int {
let node = match build_ifa_node(&iface) {
Ok(n) => n,
Err(_) => {
*ifap = head;
freeifaddrs(head);
unsafe { *ifap = head };
unsafe { freeifaddrs(head) };
platform::ERRNO.set(errno::ENOMEM);
return -1;
}
};
*tail = node;
unsafe { *tail = node };
tail = unsafe { &mut (*node).ifa_next };
}
*ifap = head;
unsafe { *ifap = head };
platform::ERRNO.set(0);
0
}
@@ -153,10 +158,13 @@ fn parse_addr_string(s: &[u8]) -> Option<([u8; 16], u8, sa_family_t)> {
let ip_part = split.next()?;
let prefix_part = split.next();
let prefix: u8 = match prefix_part {
Some(p) => match core::str::from_utf8(p).ok()?.parse().ok()? {
0..=128 => return None,
v => v,
},
Some(p) => {
let v: u8 = core::str::from_utf8(p).ok()?.parse().ok()?;
if v > 128 {
return None;
}
v
}
None => 64,
};
let mut out = [0u8; 16];
@@ -203,7 +211,7 @@ fn parse_addr_string(s: &[u8]) -> Option<([u8; 16], u8, sa_family_t)> {
if prefix > (len as u8) * 8 {
return None;
}
Some((out, prefix, if len == 4 { AF_INET } else { AF_PACKET }))
Some((out, prefix, if len == 4 { AF_INET } else { AF_INET6 }))
}
#[cfg(target_os = "redox")]
@@ -420,17 +428,29 @@ fn build_ifa_node(iface: &InterfaceInfo) -> Result<*mut ifaddrs, ()> {
unsafe {
(*addr).sin_family = AF_INET;
(*addr).sin_port = 0;
let addr_bytes = (*addr).sin_addr.s_addr.to_ne_bytes();
core::ptr::copy_nonoverlapping(
addr_bytes.as_ptr(),
iface.addr.as_ptr(),
4,
);
(*addr).sin_addr.s_addr = u32::from_ne_bytes([
iface.addr[0],
iface.addr[1],
iface.addr[2],
iface.addr[3],
]);
(*node).ifa_addr = addr_ptr;
}
} else {
let addr6 = addr_ptr as *mut sockaddr_in6;
unsafe {
(*(addr_ptr as *mut sockaddr_in6)).sin6_family = iface.addr_family;
(*addr6).sin6_family = iface.addr_family;
let sin6_addr_bytes =
core::slice::from_raw_parts_mut(
&mut (*addr6).sin6_addr as *mut _ as *mut u8,
16,
);
let copy_len = iface.addr_len.min(16) as usize;
core::ptr::copy_nonoverlapping(
iface.addr.as_ptr(),
sin6_addr_bytes.as_mut_ptr(),
copy_len,
);
(*node).ifa_addr = addr_ptr;
}
}
@@ -445,17 +465,29 @@ fn build_ifa_node(iface: &InterfaceInfo) -> Result<*mut ifaddrs, ()> {
let addr = netmask_ptr as *mut sockaddr_in;
unsafe {
(*addr).sin_family = AF_INET;
let nm_bytes = (*addr).sin_addr.s_addr.to_ne_bytes();
core::ptr::copy_nonoverlapping(
nm_bytes.as_ptr(),
iface.netmask.as_ptr(),
4,
);
(*addr).sin_addr.s_addr = u32::from_ne_bytes([
iface.netmask[0],
iface.netmask[1],
iface.netmask[2],
iface.netmask[3],
]);
(*node).ifa_netmask = netmask_ptr;
}
} else {
unsafe {
(*(netmask_ptr as *mut sockaddr_in6)).sin6_family = AF_INET as sa_family_t;
let addr6 = netmask_ptr as *mut sockaddr_in6;
(*addr6).sin6_family = AF_INET6;
let sin6_addr_bytes =
core::slice::from_raw_parts_mut(
&mut (*addr6).sin6_addr as *mut _ as *mut u8,
16,
);
let copy_len = iface.netmask_len.min(16) as usize;
core::ptr::copy_nonoverlapping(
iface.netmask.as_ptr(),
sin6_addr_bytes.as_mut_ptr(),
copy_len,
);
(*node).ifa_netmask = netmask_ptr;
}
}
+2 -2
View File
@@ -4,7 +4,7 @@ use crate::{
header::{
errno::EINVAL,
pthread::{PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED, RlctMutex, e},
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec},
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, CLOCK_PROCESS_CPUTIME_ID, timespec},
},
platform::types::{c_int, clockid_t, pthread_cond_t, pthread_condattr_t, pthread_mutex_t},
};
@@ -293,7 +293,7 @@ pub unsafe extern "C" fn pthread_condattr_setclock(
// POSIX: only CLOCK_REALTIME and CLOCK_MONOTONIC are portable clocks for
// condition variable timeouts. Any other clock_id must fail with EINVAL.
match clock_id {
CLOCK_REALTIME | CLOCK_MONOTONIC => {
CLOCK_REALTIME | CLOCK_MONOTONIC | CLOCK_PROCESS_CPUTIME_ID => {
(unsafe { *attr.cast::<RlctCondAttr>() }).clock = clock_id;
0
}
+30 -7
View File
@@ -109,12 +109,17 @@ const fn default_rlimits() -> [rlimit; RLIM_COUNT] {
/// Fields parsed from the kernel proc scheme's Linux-compatible stat line,
/// used by `getrusage`. The kernel reports `utime`/`stime` in whole seconds
/// and `rss` in pages. Per-process fault and context-switch counters are
/// currently hardwired to zero by the kernel proc scheme.
/// and `rss` in pages. The kernel currently hardwires fault counters
/// (`minflt`/`majflt`) to zero, but relibc parses them so they will be
/// reported automatically once the kernel starts tracking real values.
/// Context-switch and I/O counters (`inblock`, `oublock`, `nvcsw`,
/// `nivcsw`) are not present in the proc stat line at all.
struct ProcStatFields {
utime_sec: u64,
stime_sec: u64,
rss_pages: u64,
minflt: u64,
majflt: u64,
}
/// Read and parse `/scheme/proc/<pid>/stat` from the kernel proc scheme.
@@ -156,6 +161,8 @@ fn read_proc_stat_fields(pid: usize) -> Option<ProcStatFields> {
utime_sec: parse(11)?,
stime_sec: parse(12)?,
rss_pages: parse(21).unwrap_or(0),
minflt: parse(7).unwrap_or(0),
majflt: parse(9).unwrap_or(0),
})
}
@@ -324,8 +331,20 @@ impl Pal for Sys {
}
unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()> {
todo_skip!(0, "clock_settime({}, {:p}): not implemented", clk_id, tp);
Err(Errno(ENOSYS))
if tp.is_null() {
return Err(Errno(EINVAL));
}
let relibc_ts = unsafe { &*tp };
let redox_tp = syscall::TimeSpec {
tv_sec: relibc_ts.tv_sec as i64,
tv_nsec: relibc_ts.tv_nsec as i64,
};
syscall::syscall2(
syscall::SYS_CLOCK_SETTIME,
clk_id as usize,
&redox_tp as *const _ as usize,
)?;
Ok(())
}
fn close(fd: c_int) -> Result<()> {
@@ -886,6 +905,8 @@ impl Pal for Sys {
utime_sec: 0,
stime_sec: 0,
rss_pages: 0,
minflt: 0,
majflt: 0,
});
// ru_maxrss is in kilobytes (Linux convention); rss from the stat
@@ -905,10 +926,12 @@ impl Pal for Sys {
ru_ixrss: 0,
ru_idrss: 0,
ru_isrss: 0,
// The kernel proc scheme hardwires fault counters to zero today.
ru_minflt: 0,
ru_majflt: 0,
ru_minflt: stat.minflt as c_long,
ru_majflt: stat.majflt as c_long,
ru_nswap: 0,
// The proc stat line does not include I/O or context-switch
// counters; these require /proc/<pid>/io or /proc/<pid>/status
// interfaces that the Redox proc scheme does not expose today.
ru_inblock: 0,
ru_oublock: 0,
ru_msgsnd: 0,