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::{
|
use crate::{
|
||||||
header::{
|
header::{
|
||||||
errno, stdlib,
|
errno, stdlib,
|
||||||
netinet_in::{sockaddr_in, sockaddr_in6, AF_INET},
|
bits_safamily_t::sa_family_t,
|
||||||
sys_socket::{sa_family_t, sockaddr, AF_PACKET},
|
netinet_in::{sockaddr_in, sockaddr_in6},
|
||||||
|
sys_socket::{sockaddr},
|
||||||
},
|
},
|
||||||
platform::{
|
platform::{
|
||||||
self,
|
self,
|
||||||
@@ -14,6 +15,7 @@ use crate::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use alloc::vec::Vec;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
@@ -21,6 +23,9 @@ const O_RDONLY: usize = 0;
|
|||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
const O_DIRECTORY: usize = 0x10000;
|
const O_DIRECTORY: usize = 0x10000;
|
||||||
|
|
||||||
|
const AF_INET: sa_family_t = 2;
|
||||||
|
const AF_INET6: sa_family_t = 10;
|
||||||
|
|
||||||
#[cfg(target_os = "redox")]
|
#[cfg(target_os = "redox")]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct Dirent {
|
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 head: *mut ifaddrs = ptr::null_mut();
|
||||||
let mut tail: *mut *mut ifaddrs = &mut head;
|
let mut tail: *mut *mut ifaddrs = &mut head;
|
||||||
let Ok(interfaces) = enumerate_interfaces() else {
|
let Ok(interfaces) = enumerate_interfaces() else {
|
||||||
*ifap = ptr::null_mut();
|
unsafe { *ifap = ptr::null_mut() };
|
||||||
platform::ERRNO.set(errno::ENOSYS);
|
platform::ERRNO.set(errno::ENOSYS);
|
||||||
return -1;
|
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) {
|
let node = match build_ifa_node(&iface) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
*ifap = head;
|
unsafe { *ifap = head };
|
||||||
freeifaddrs(head);
|
unsafe { freeifaddrs(head) };
|
||||||
platform::ERRNO.set(errno::ENOMEM);
|
platform::ERRNO.set(errno::ENOMEM);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
*tail = node;
|
unsafe { *tail = node };
|
||||||
tail = unsafe { &mut (*node).ifa_next };
|
tail = unsafe { &mut (*node).ifa_next };
|
||||||
}
|
}
|
||||||
|
|
||||||
*ifap = head;
|
unsafe { *ifap = head };
|
||||||
platform::ERRNO.set(0);
|
platform::ERRNO.set(0);
|
||||||
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 ip_part = split.next()?;
|
||||||
let prefix_part = split.next();
|
let prefix_part = split.next();
|
||||||
let prefix: u8 = match prefix_part {
|
let prefix: u8 = match prefix_part {
|
||||||
Some(p) => match core::str::from_utf8(p).ok()?.parse().ok()? {
|
Some(p) => {
|
||||||
0..=128 => return None,
|
let v: u8 = core::str::from_utf8(p).ok()?.parse().ok()?;
|
||||||
v => v,
|
if v > 128 {
|
||||||
},
|
return None;
|
||||||
|
}
|
||||||
|
v
|
||||||
|
}
|
||||||
None => 64,
|
None => 64,
|
||||||
};
|
};
|
||||||
let mut out = [0u8; 16];
|
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 {
|
if prefix > (len as u8) * 8 {
|
||||||
return None;
|
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")]
|
#[cfg(target_os = "redox")]
|
||||||
@@ -420,17 +428,29 @@ fn build_ifa_node(iface: &InterfaceInfo) -> Result<*mut ifaddrs, ()> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
(*addr).sin_family = AF_INET;
|
(*addr).sin_family = AF_INET;
|
||||||
(*addr).sin_port = 0;
|
(*addr).sin_port = 0;
|
||||||
let addr_bytes = (*addr).sin_addr.s_addr.to_ne_bytes();
|
(*addr).sin_addr.s_addr = u32::from_ne_bytes([
|
||||||
core::ptr::copy_nonoverlapping(
|
iface.addr[0],
|
||||||
addr_bytes.as_ptr(),
|
iface.addr[1],
|
||||||
iface.addr.as_ptr(),
|
iface.addr[2],
|
||||||
4,
|
iface.addr[3],
|
||||||
);
|
]);
|
||||||
(*node).ifa_addr = addr_ptr;
|
(*node).ifa_addr = addr_ptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let addr6 = addr_ptr as *mut sockaddr_in6;
|
||||||
unsafe {
|
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;
|
(*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;
|
let addr = netmask_ptr as *mut sockaddr_in;
|
||||||
unsafe {
|
unsafe {
|
||||||
(*addr).sin_family = AF_INET;
|
(*addr).sin_family = AF_INET;
|
||||||
let nm_bytes = (*addr).sin_addr.s_addr.to_ne_bytes();
|
(*addr).sin_addr.s_addr = u32::from_ne_bytes([
|
||||||
core::ptr::copy_nonoverlapping(
|
iface.netmask[0],
|
||||||
nm_bytes.as_ptr(),
|
iface.netmask[1],
|
||||||
iface.netmask.as_ptr(),
|
iface.netmask[2],
|
||||||
4,
|
iface.netmask[3],
|
||||||
);
|
]);
|
||||||
(*node).ifa_netmask = netmask_ptr;
|
(*node).ifa_netmask = netmask_ptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsafe {
|
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;
|
(*node).ifa_netmask = netmask_ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::{
|
|||||||
header::{
|
header::{
|
||||||
errno::EINVAL,
|
errno::EINVAL,
|
||||||
pthread::{PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED, RlctMutex, e},
|
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},
|
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
|
// POSIX: only CLOCK_REALTIME and CLOCK_MONOTONIC are portable clocks for
|
||||||
// condition variable timeouts. Any other clock_id must fail with EINVAL.
|
// condition variable timeouts. Any other clock_id must fail with EINVAL.
|
||||||
match clock_id {
|
match clock_id {
|
||||||
CLOCK_REALTIME | CLOCK_MONOTONIC => {
|
CLOCK_REALTIME | CLOCK_MONOTONIC | CLOCK_PROCESS_CPUTIME_ID => {
|
||||||
(unsafe { *attr.cast::<RlctCondAttr>() }).clock = clock_id;
|
(unsafe { *attr.cast::<RlctCondAttr>() }).clock = clock_id;
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,12 +109,17 @@ const fn default_rlimits() -> [rlimit; RLIM_COUNT] {
|
|||||||
|
|
||||||
/// Fields parsed from the kernel proc scheme's Linux-compatible stat line,
|
/// Fields parsed from the kernel proc scheme's Linux-compatible stat line,
|
||||||
/// used by `getrusage`. The kernel reports `utime`/`stime` in whole seconds
|
/// used by `getrusage`. The kernel reports `utime`/`stime` in whole seconds
|
||||||
/// and `rss` in pages. Per-process fault and context-switch counters are
|
/// and `rss` in pages. The kernel currently hardwires fault counters
|
||||||
/// currently hardwired to zero by the kernel proc scheme.
|
/// (`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 {
|
struct ProcStatFields {
|
||||||
utime_sec: u64,
|
utime_sec: u64,
|
||||||
stime_sec: u64,
|
stime_sec: u64,
|
||||||
rss_pages: u64,
|
rss_pages: u64,
|
||||||
|
minflt: u64,
|
||||||
|
majflt: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read and parse `/scheme/proc/<pid>/stat` from the kernel proc scheme.
|
/// 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)?,
|
utime_sec: parse(11)?,
|
||||||
stime_sec: parse(12)?,
|
stime_sec: parse(12)?,
|
||||||
rss_pages: parse(21).unwrap_or(0),
|
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<()> {
|
unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()> {
|
||||||
todo_skip!(0, "clock_settime({}, {:p}): not implemented", clk_id, tp);
|
if tp.is_null() {
|
||||||
Err(Errno(ENOSYS))
|
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<()> {
|
fn close(fd: c_int) -> Result<()> {
|
||||||
@@ -886,6 +905,8 @@ impl Pal for Sys {
|
|||||||
utime_sec: 0,
|
utime_sec: 0,
|
||||||
stime_sec: 0,
|
stime_sec: 0,
|
||||||
rss_pages: 0,
|
rss_pages: 0,
|
||||||
|
minflt: 0,
|
||||||
|
majflt: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// ru_maxrss is in kilobytes (Linux convention); rss from the stat
|
// ru_maxrss is in kilobytes (Linux convention); rss from the stat
|
||||||
@@ -905,10 +926,12 @@ impl Pal for Sys {
|
|||||||
ru_ixrss: 0,
|
ru_ixrss: 0,
|
||||||
ru_idrss: 0,
|
ru_idrss: 0,
|
||||||
ru_isrss: 0,
|
ru_isrss: 0,
|
||||||
// The kernel proc scheme hardwires fault counters to zero today.
|
ru_minflt: stat.minflt as c_long,
|
||||||
ru_minflt: 0,
|
ru_majflt: stat.majflt as c_long,
|
||||||
ru_majflt: 0,
|
|
||||||
ru_nswap: 0,
|
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_inblock: 0,
|
||||||
ru_oublock: 0,
|
ru_oublock: 0,
|
||||||
ru_msgsnd: 0,
|
ru_msgsnd: 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user