Skip to content

Commit 7dffd7f

Browse files
committed
feat(wrap): fallback proc scan for first_child_pid_of
1 parent 328198e commit 7dffd7f

1 file changed

Lines changed: 33 additions & 5 deletions

File tree

src/wrap.rs

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

116-
match first_child.parse::<libc::pid_t>() {
117-
Ok(v) => Ok(v),
118-
_ => Err(anyhow!("failed to find child PID")),
125+
// Fallback: scan /proc for a process whose PPid matches parent.
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+
// Only look at numeric directories (PIDs).
132+
if !name_str.chars().next().map_or(false, |c| c.is_ascii_digit()) {
133+
continue;
134+
}
135+
let status_path = format!("/proc/{name_str}/status");
136+
if let Ok(status) = fs::read_to_string(&status_path) {
137+
if status.lines().any(|line| line == ppid_needle) {
138+
if let Ok(pid) = name_str.parse::<libc::pid_t>() {
139+
return Ok(pid);
140+
}
141+
}
142+
}
119143
}
144+
145+
Err(anyhow!(
146+
"failed to find child PID of {parent} (no children file, /proc scan found nothing)"
147+
))
120148
}
121149

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

0 commit comments

Comments
 (0)