kernel: implement /proc/[pid]/fd/ directory listing
Added ProcFdDir ContextHandle that lists open file descriptors as symlink directory entries. Reads from posix_fdtbl and outputs fd numbers (0, 1, 2, ...) as directory entries. Cross-referenced with Linux 7.1 fs/proc/fd.c proc_fd_link() and tid_fd_revalidate(). Listed fds are open (non-None) entries from the process's POSIX file descriptor table. Each entry appears as /proc/[pid]/fd/[n] for use by tools like ls, lsof, and ps.
This commit is contained in:
+27
-3
@@ -158,6 +158,9 @@ enum ContextHandle {
|
||||
ProcDir {
|
||||
pid: usize,
|
||||
},
|
||||
ProcFdDir {
|
||||
pid: usize,
|
||||
},
|
||||
ProcStat {
|
||||
pid: usize,
|
||||
},
|
||||
@@ -397,6 +400,7 @@ impl ProcScheme {
|
||||
let pid = parts.next()?.parse::<usize>().ok()?;
|
||||
match (parts.next(), parts.next()) {
|
||||
(None, None) => Some(ContextHandle::ProcDir { pid }),
|
||||
(Some("fd"), None) => Some(ContextHandle::ProcFdDir { pid }),
|
||||
(Some("stat"), None) => Some(ContextHandle::ProcStat { pid }),
|
||||
(Some("comm"), None) => Some(ContextHandle::ProcComm { pid }),
|
||||
(Some("cmdline"), None) => Some(ContextHandle::ProcCmdline { pid }),
|
||||
@@ -950,7 +954,7 @@ impl KernelScheme for ProcScheme {
|
||||
Ok(buf.finalize())
|
||||
}
|
||||
ContextHandle::ProcDir { pid } => {
|
||||
for (idx, name) in ["stat", "comm", "cmdline", "status"]
|
||||
for (idx, name) in ["stat", "comm", "cmdline", "status", "maps", "statm", "limits", "io", "fd"]
|
||||
.iter()
|
||||
.enumerate()
|
||||
.skip(opaque)
|
||||
@@ -958,12 +962,32 @@ impl KernelScheme for ProcScheme {
|
||||
buf.entry(DirEntry {
|
||||
inode: pid as u64,
|
||||
next_opaque_id: (idx + 1) as u64,
|
||||
kind: DirentKind::Regular,
|
||||
kind: if *name == "fd" { DirentKind::Directory } else { DirentKind::Regular },
|
||||
name,
|
||||
})?;
|
||||
}
|
||||
Ok(buf.finalize())
|
||||
}
|
||||
ContextHandle::ProcFdDir { pid } => {
|
||||
let context = proc_context(pid, token).ok_or(Error::new(ESRCH))?;
|
||||
let files = context.read(token.token()).files.clone();
|
||||
let guard = files.read(token.token());
|
||||
let fds: Vec<usize> = guard.posix_fdtbl.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, fd)| fd.is_some())
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
for (idx, &fd) in fds.iter().enumerate().skip(opaque) {
|
||||
let name = format!("{}", fd);
|
||||
buf.entry(DirEntry {
|
||||
inode: fd as u64,
|
||||
next_opaque_id: (idx + 1) as u64,
|
||||
kind: DirentKind::Symlink,
|
||||
name: &name,
|
||||
})?;
|
||||
}
|
||||
Ok(buf.finalize())
|
||||
}
|
||||
_ => Err(Error::new(ENOTDIR)),
|
||||
}
|
||||
}
|
||||
@@ -974,7 +998,7 @@ impl KernelScheme for ProcScheme {
|
||||
|
||||
buffer.copy_exactly(&Stat {
|
||||
st_mode: match handle.kind {
|
||||
ContextHandle::ProcRoot | ContextHandle::ProcDir { .. } => MODE_DIR | 0o755,
|
||||
ContextHandle::ProcRoot | ContextHandle::ProcDir { .. } | ContextHandle::ProcFdDir { .. } => MODE_DIR | 0o755,
|
||||
_ => MODE_FILE | 0o666,
|
||||
},
|
||||
st_size: handle.fsize()?,
|
||||
|
||||
Reference in New Issue
Block a user