pub const ARG_MAX_CAP: usize = 64 * 1024;
pub fn parse_procargs2(buf: &[u8]) -> Option<String> {
if buf.len() < 4 {
return None;
}
let argc = u32::from_ne_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize;
if argc == 0 || argc > 4096 {
return None;
}
let mut rest = &buf[4..];
let nul = rest.iter().position(|b| *b == 0)?;
rest = &rest[nul + 1..];
while rest.first() == Some(&0) {
rest = &rest[1..];
}
let mut parts: Vec<String> = Vec::with_capacity(argc.min(64));
for _ in 0..argc {
if rest.is_empty() {
break;
}
let end = rest.iter().position(|b| *b == 0).unwrap_or(rest.len());
if end == 0 {
break;
}
parts.push(String::from_utf8_lossy(&rest[..end]).into_owned());
rest = if end < rest.len() {
&rest[end + 1..]
} else {
&[]
};
}
if parts.is_empty() {
None
} else {
Some(parts.join(" "))
}
}
pub fn state_letter(p_stat: i8) -> u8 {
match p_stat {
1 => b'I', 2 => b'R', 3 => b'S', 4 => b'T', 5 => b'Z', _ => b'?',
}
}
#[cfg(test)]
mod tests {
use super::*;
fn procargs2(argc: u32, path: &str, argv: &[&str]) -> Vec<u8> {
let mut buf = Vec::new();
buf.extend_from_slice(&argc.to_ne_bytes());
buf.extend_from_slice(path.as_bytes());
buf.push(0);
buf.extend_from_slice(&[0, 0, 0]);
for (i, a) in argv.iter().enumerate() {
if i > 0 {
buf.push(0);
}
buf.extend_from_slice(a.as_bytes());
}
buf.push(0);
buf.extend_from_slice(b"HOME=/Users/x\0SHELL=/bin/zsh\0");
buf
}
#[test]
fn procargs2_basic() {
let buf = procargs2(3, "/usr/bin/vim", &["vim", "-u", "NONE", "file.txt"][..3]);
assert_eq!(parse_procargs2(&buf).as_deref(), Some("vim -u NONE"));
}
#[test]
fn procargs2_stops_at_argc() {
let buf = procargs2(2, "/bin/sh", &["sh", "-c", "echo hi"]);
assert_eq!(
parse_procargs2(&buf).as_deref(),
Some("sh -c"),
"argv beyond argc must not be included"
);
}
#[test]
fn procargs2_rejects_truncated_and_zero() {
assert!(parse_procargs2(&[]).is_none());
assert!(parse_procargs2(&[0, 0, 0]).is_none());
assert!(parse_procargs2(&0u32.to_ne_bytes()).is_none(), "argc == 0");
}
#[test]
fn procargs2_handles_args_with_spaces() {
let buf = procargs2(2, "/bin/echo", &["echo", "hello world"]);
assert_eq!(parse_procargs2(&buf).as_deref(), Some("echo hello world"));
}
#[test]
fn state_letters() {
assert_eq!(state_letter(2), b'R');
assert_eq!(state_letter(3), b'S');
assert_eq!(state_letter(4), b'T');
assert_eq!(state_letter(5), b'Z');
assert_eq!(state_letter(1), b'I');
assert_eq!(state_letter(99), b'?');
}
}