relibc: complete round-9 fixes and repair ifaddrs compilation
Builds ona41c5cb0(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 ind9760bdcbut 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:
+58
-26
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user