Skip to content

Commit 80fa255

Browse files
committed
fix(sort): use native sysctl for percentage buffer-size on BSD platforms
Replace subprocess-based sysctl calls with native libc::sysctl() syscalls for macOS, FreeBSD, OpenBSD, and NetBSD to fix test_buffer_sizes failure in CI environments. The previous implementation spawned sysctl subprocesses which could fail in sandboxed GitHub Actions runners. The native approach is more reliable, performant, and includes subprocess fallback for robustness. Fixes percentage-based buffer size parsing (e.g., sort -S 10%)
1 parent 8fae6fc commit 80fa255

File tree

1 file changed

+109
-4
lines changed

1 file changed

+109
-4
lines changed

src/uucore/src/lib/features/parser/parse_size.rs

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,33 @@ pub fn available_memory_bytes() -> Option<u128> {
7979

8080
/// Get the total number of bytes of physical memory on macOS.
8181
///
82-
/// Uses the `sysctl` command to query `hw.memsize`.
82+
/// Uses native `sysctl` syscall to query `hw.memsize`, with subprocess fallback.
8383
#[cfg(target_os = "macos")]
8484
fn total_physical_memory() -> Result<u128, SystemError> {
85+
use std::mem;
86+
use std::ptr;
87+
88+
// Try native sysctl syscall first (more reliable in restricted environments)
89+
let mut size: u64 = 0;
90+
let mut len = mem::size_of::<u64>();
91+
let mut mib = [libc::CTL_HW, libc::HW_MEMSIZE];
92+
93+
let result = unsafe {
94+
libc::sysctl(
95+
mib.as_mut_ptr(),
96+
2,
97+
&mut size as *mut _ as *mut libc::c_void,
98+
&mut len,
99+
ptr::null_mut(),
100+
0,
101+
)
102+
};
103+
104+
if result == 0 {
105+
return Ok(size as u128);
106+
}
107+
108+
// Fallback to subprocess if native call fails
85109
let output = std::process::Command::new("sysctl")
86110
.arg("-n")
87111
.arg("hw.memsize")
@@ -94,9 +118,36 @@ fn total_physical_memory() -> Result<u128, SystemError> {
94118

95119
/// Get the total number of bytes of physical memory on FreeBSD.
96120
///
97-
/// Uses the `sysctl` command to query `hw.physmem`.
121+
/// Uses native `sysctl` syscall to query `hw.physmem`, with subprocess fallback.
98122
#[cfg(target_os = "freebsd")]
99123
fn total_physical_memory() -> Result<u128, SystemError> {
124+
use std::mem;
125+
use std::ptr;
126+
127+
// HW_PHYSMEM constant (not always exported by libc)
128+
const HW_PHYSMEM: libc::c_int = 5;
129+
130+
// Try native sysctl syscall first (more reliable in restricted environments)
131+
let mut size: u64 = 0;
132+
let mut len = mem::size_of::<u64>();
133+
let mut mib = [libc::CTL_HW, HW_PHYSMEM];
134+
135+
let result = unsafe {
136+
libc::sysctl(
137+
mib.as_mut_ptr(),
138+
2,
139+
ptr::from_mut(&mut size).cast::<libc::c_void>(),
140+
&mut len,
141+
ptr::null_mut(),
142+
0,
143+
)
144+
};
145+
146+
if result == 0 {
147+
return Ok(size as u128);
148+
}
149+
150+
// Fallback to subprocess if native call fails
100151
let output = std::process::Command::new("sysctl")
101152
.arg("-n")
102153
.arg("hw.physmem")
@@ -109,9 +160,36 @@ fn total_physical_memory() -> Result<u128, SystemError> {
109160

110161
/// Get the total number of bytes of physical memory on OpenBSD.
111162
///
112-
/// Uses the `sysctl` command to query `hw.physmem`.
163+
/// Uses native `sysctl` syscall to query `hw.physmem`, with subprocess fallback.
113164
#[cfg(target_os = "openbsd")]
114165
fn total_physical_memory() -> Result<u128, SystemError> {
166+
use std::mem;
167+
use std::ptr;
168+
169+
// HW_PHYSMEM constant (not always exported by libc)
170+
const HW_PHYSMEM: libc::c_int = 19;
171+
172+
// Try native sysctl syscall first (more reliable in restricted environments)
173+
let mut size: u64 = 0;
174+
let mut len = mem::size_of::<u64>();
175+
let mut mib = [libc::CTL_HW, HW_PHYSMEM];
176+
177+
let result = unsafe {
178+
libc::sysctl(
179+
mib.as_mut_ptr(),
180+
2,
181+
ptr::from_mut(&mut size).cast::<libc::c_void>(),
182+
&mut len,
183+
ptr::null_mut(),
184+
0,
185+
)
186+
};
187+
188+
if result == 0 {
189+
return Ok(size as u128);
190+
}
191+
192+
// Fallback to subprocess if native call fails
115193
let output = std::process::Command::new("sysctl")
116194
.arg("-n")
117195
.arg("hw.physmem")
@@ -124,9 +202,36 @@ fn total_physical_memory() -> Result<u128, SystemError> {
124202

125203
/// Get the total number of bytes of physical memory on NetBSD.
126204
///
127-
/// Uses the `sysctl` command to query `hw.physmem64`.
205+
/// Uses native `sysctl` syscall to query `hw.physmem64`, with subprocess fallback.
128206
#[cfg(target_os = "netbsd")]
129207
fn total_physical_memory() -> Result<u128, SystemError> {
208+
use std::mem;
209+
use std::ptr;
210+
211+
// HW_PHYSMEM64 constant (not always exported by libc)
212+
const HW_PHYSMEM64: libc::c_int = 9;
213+
214+
// Try native sysctl syscall first (more reliable in restricted environments)
215+
let mut size: u64 = 0;
216+
let mut len = mem::size_of::<u64>();
217+
let mut mib = [libc::CTL_HW, HW_PHYSMEM64];
218+
219+
let result = unsafe {
220+
libc::sysctl(
221+
mib.as_mut_ptr(),
222+
2,
223+
ptr::from_mut(&mut size).cast::<libc::c_void>(),
224+
&mut len,
225+
ptr::null_mut(),
226+
0,
227+
)
228+
};
229+
230+
if result == 0 {
231+
return Ok(size as u128);
232+
}
233+
234+
// Fallback to subprocess if native call fails
130235
let output = std::process::Command::new("sysctl")
131236
.arg("-n")
132237
.arg("hw.physmem64")

0 commit comments

Comments
 (0)