Skip to content

Commit 2740337

Browse files
authored
Merge pull request #92 from noeljackson/feat/child-pid-fallback
feat(wrap): fallback proc scan for first_child_pid_of
2 parents 776de30 + ad7362f commit 2740337

1 file changed

Lines changed: 30 additions & 5 deletions

File tree

src/wrap.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,39 @@ fn fork_and_wait() -> Result<()> {
108108
/// The reason we need this is because we actually need to attach to the
109109
/// *supervised* process, not the *supervisor* process, which exists in
110110
/// a different set of namespaces than the ones we want to attach to.
111+
///
112+
/// Tries `/proc/<pid>/task/<pid>/children` first (requires CONFIG_PROC_CHILDREN),
113+
/// then falls back to scanning `/proc` for processes whose PPid matches.
111114
fn first_child_pid_of(parent: libc::pid_t) -> Result<libc::pid_t> {
112-
let child_set = fs::read_to_string(format!("/proc/{parent}/task/{parent}/children"))?;
113-
let first_child = child_set.split(" ").collect::<Vec<_>>()[0];
115+
// Fast path: use the children file if available (CONFIG_PROC_CHILDREN=y).
116+
let children_path = format!("/proc/{parent}/task/{parent}/children");
117+
if let Ok(child_set) = fs::read_to_string(&children_path) {
118+
let first_child = child_set.split(' ').next().unwrap_or("");
119+
if let Ok(v) = first_child.parse::<libc::pid_t>() {
120+
return Ok(v);
121+
}
122+
}
114123

115-
match first_child.parse::<libc::pid_t>() {
116-
Ok(v) => Ok(v),
117-
_ => Err(anyhow!("failed to find child PID")),
124+
// Fallback: scan /proc for a process whose PPid matches parent.
125+
debug!("children file unavailable for pid {parent}, falling back to /proc scan");
126+
let ppid_needle = format!("PPid:\t{parent}");
127+
for entry in fs::read_dir("/proc")? {
128+
let entry = entry?;
129+
let name = entry.file_name();
130+
let name_str = name.to_string_lossy();
131+
if !name_str.chars().next().is_some_and(|c| c.is_ascii_digit()) {
132+
continue;
133+
}
134+
let status_path = format!("/proc/{name_str}/status");
135+
if let Ok(status) = fs::read_to_string(&status_path)
136+
&& status.lines().any(|line| line == ppid_needle)
137+
&& let Ok(pid) = name_str.parse::<libc::pid_t>()
138+
{
139+
return Ok(pid);
140+
}
118141
}
142+
143+
Err(anyhow!("failed to find child PID of {parent}"))
119144
}
120145

121146
fn render_uidgid_mappings(mappings: &[IdMapping]) -> String {

0 commit comments

Comments
 (0)