如何忽略由read_dir创建的文件描述符?

编程语言 2026-07-10

我试图通过访问 /proc/[process_pid]/fd 来列出某个进程打开的所有文件描述符。

我的代码:

    pub fn list_fds(&self) -> Option<Vec<usize>> {
        let mut fd_vec: Vec<usize> = Vec::new();
        let linux_process_fd_path_string = format!("/proc/{}/fd", self.pid);
        let linux_process_fd_path = Path::new(&linux_process_fd_path_string);

        let entries = fs::read_dir(linux_process_fd_path).ok()?;

        if linux_process_fd_path.is_dir() {
            for entry in entries {
                let entry = entry.ok()?;
                let filename_uszie = entry.file_name().to_string_lossy().parse::<usize>().ok()?;
                fd_vec.push(filename_uszie);
            }
        }
        //fd_vec.pop();       // I don't know if this is appropriate to ignore fd created by read_dir
        Some(fd_vec)
    }

测试代码:

    #[test]
    fn test_list_fds() {
        let mut test_subprocess = start_c_program("./multi_pipe_test");
        let process = ps_utils::get_target("multi_pipe_test").unwrap().unwrap();
        assert_eq!(
            process
                .list_fds()
                .expect("Expected list_fds to find file descriptors, but it returned None"),
            vec![0, 1, 2, 4, 5]
        );
        let _ = test_subprocess.kill();
    }

输出:

---- process::test::test_list_fds stdout ----

thread 'process::test::test_list_fds' (52275) panicked at src/process.rs:75:9:
assertion `left == right` failed
  left: [0, 1, 2, 4, 5, 103]
 right: [0, 1, 2, 4, 5]
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

然后我发现该函数在调用read_dir时可能会创建一个文件描述符。

我尝试去掉最后一个文件描述符,但不确定是否合适(显然不可取)。

忽略这个文件描述符的最佳实践是什么?

解决方案

dirfd() 函数返回DIR结构体的底层文件描述符。

下面是一个简单的C 程序,显示 "/proc//fd" 的内容,并排除与 opendir() 服务对应的条目:

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>

int main(void)
{
  DIR *dd;
  struct dirent *de;
  ssize_t sz;
  char myFdDir[256];
  char buf[256];
  int rc, rc1;
  char fdToExclude[20];
  int fd;

  // My fd list directory
  rc = snprintf(myFdDir, sizeof(myFdDir), "/proc/%d/fd", getpid());

  // Open my fd list directory (this creates a brand-new file descriptor)
  dd = opendir(myFdDir);

  snprintf(fdToExclude, sizeof(fdToExclude), "%d",  dirfd(dd));

  // Read the content of the directory
  while ((de = readdir(dd)))
  {
    // Ignore current and father directories
    if (!strcmp(de->d_name, ".") ||
        !strcmp(de->d_name, ".."))
      continue;

    // Ignore fd of opendir()
    if (!strcmp(fdToExclude, de->d_name))
      continue;

    // Absolute pathname of the symbolic link
    rc1 = snprintf(&(myFdDir[rc]), sizeof(myFdDir) - rc, "/%s", de->d_name);

    // Get the content of the symbolic link
    sz = readlink(myFdDir, buf, sizeof(buf));
    buf[sz] = '\0';

    // Restore my fd list directory name
    myFdDir[rc] = '\0';

    printf("%s -> %s\n", de->d_name, buf);
  }

  closedir(dd);

  return 0;
}
$ gcc myfds.c -o myfds
$ ./myfds
0 -> /dev/pts/3
1 -> /dev/pts/3
2 -> /dev/pts/3
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章