use std::path::Path;
const NAMESPACE_PID_LINE: &str = "NSpid:";
fn numbers_of(status: &str) -> Option<Vec<i64>> {
let line: &str = status.lines().find_map(|line| { return line.strip_prefix(NAMESPACE_PID_LINE); })?;
let mut numbers: Vec<i64> = Vec::new();
for field in line.split_whitespace() {
numbers.push(field.parse::<i64>().ok()?);
}
return Some(numbers);
}
pub fn nested_holders_of(proc_root: &Path, number: i64) -> Result<Vec<i64>, String> {
let listing: std::fs::ReadDir = std::fs::read_dir(proc_root).map_err(|error| { return format!("{}: {error}", proc_root.display()); })?;
let mut holders: Vec<i64> = Vec::new();
for item in listing.flatten() {
let Some(outer) = item.file_name().to_str().and_then(|name| { return name.parse::<i64>().ok(); }) else {
continue;
};
let status: String = match std::fs::read_to_string(item.path().join("status")) {
Ok(text) => text,
Err(error) if error.kind() == std::io::ErrorKind::NotFound || error.raw_os_error() == Some(libc::ESRCH) => continue,
Err(error) => return Err(format!("the status of process {outer} could not be read: {error}")),
};
let Some(numbers) = numbers_of(status.as_str()) else {
return Err(format!("the status of process {outer} lists no `{NAMESPACE_PID_LINE}` line"));
};
if numbers.iter().skip(1).any(|nested| { return *nested == number; }) {
holders.push(outer);
}
}
holders.sort_unstable();
return Ok(holders);
}
#[cfg(test)]
#[path = "stale_ref_lock_nested_numbers_tests.rs"]
mod tests;