查找Linux进程的打开文件描述符(C代码)?

发布于 2024-11-18 07:37:52 字数 59 浏览 3 评论 0原文

我想找到Linux中某个进程打开的所有fd。

我可以用 glib 库函数来做到这一点吗?

I wanted to find all fds opened for a process in linux.

Can I do it with glib library functions ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

昔梦 2024-11-25 07:37:52

这是我曾经使用过的一些代码,我不知道 /proc/self (谢谢 Donal!),但无论如何这种方式可能更通用。我已经在顶部包含了所有功能所需的内容。

#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/resource.h>

#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

/* implementation of Donal Fellows method */ 
int get_num_fds()
{
     int fd_count;
     char buf[64];
     struct dirent *dp;

     snprintf(buf, 64, "/proc/%i/fd/", getpid());

     fd_count = 0;
     DIR *dir = opendir(buf);
     while ((dp = readdir(dir)) != NULL) {
          fd_count++;
     }
     closedir(dir);
     return fd_count;
}

我曾经遇到过一个非常严重的文件句柄泄漏问题,结果证明我实际上编写了 Tom H. 建议的解决方案:

/* check whether a file-descriptor is valid */
int pth_util_fd_valid(int fd)
{
     if (fd < 3 || fd >= FD_SETSIZE)
          return FALSE;
     if (fcntl(fd, F_GETFL) == -1 && errno == EBADF)
          return FALSE;
     return TRUE;
}

/* check first 1024 (usual size of FD_SESIZE) file handles */
int test_fds()
{
     int i;
     int fd_dup;
     char errst[64];
     for (i = 0; i < FD_SETSIZE; i++) {
          *errst = 0;
          fd_dup = dup(i);
          if (fd_dup == -1) {
                strcpy(errst, strerror(errno));
                // EBADF  oldfd isn’t an open file descriptor, or newfd is out of the allowed range for file descriptors.
                // EBUSY  (Linux only) This may be returned by dup2() during a race condition with open(2) and dup().
                // EINTR  The dup2() call was interrupted by a signal; see signal(7).
                // EMFILE The process already has the maximum number of file descriptors open and tried to open a new one.
          } else {
                close(fd_dup);
                strcpy(errst, "dup() ok");
          }
          printf("%4i: %5i %24s %s\n", i, fcntl(i, F_GETOWN), fd_info(i), errst);
     }
     return 0;
}

您可能也需要这些,以满足上面最后一个 printf 的要求...

char *fcntl_flags(int flags)
{
    static char output[128];
    *output = 0;

    if (flags & O_RDONLY)
        strcat(output, "O_RDONLY ");
    if (flags & O_WRONLY)
        strcat(output, "O_WRONLY ");
    if (flags & O_RDWR)
        strcat(output, "O_RDWR ");
    if (flags & O_CREAT)
        strcat(output, "O_CREAT ");
    if (flags & O_EXCL)
        strcat(output, "O_EXCL ");
    if (flags & O_NOCTTY)
        strcat(output, "O_NOCTTY ");
    if (flags & O_TRUNC)
        strcat(output, "O_TRUNC ");
    if (flags & O_APPEND)
        strcat(output, "O_APPEND ");
    if (flags & O_NONBLOCK)
        strcat(output, "O_NONBLOCK ");
    if (flags & O_SYNC)
        strcat(output, "O_SYNC ");
    if (flags & O_ASYNC)
        strcat(output, "O_ASYNC ");

    return output;
}

char *fd_info(int fd)
{
    if (fd < 0 || fd >= FD_SETSIZE)
        return FALSE;
    // if (fcntl(fd, F_GETFL) == -1 && errno == EBADF)
    int rv = fcntl(fd, F_GETFL);
    return (rv == -1) ? strerror(errno) : fcntl_flags(rv);
}

FD_SETSIZE 通常为 1024,并且每个进程的最大文件数通常为 1024。如果您想确定,可以用对此函数的调用来替换它,如 TomH 所描述的。

#include <sys/time.h>
#include <sys/resource.h>

rlim_t get_rlimit_files()
{
    struct rlimit rlim;
    getrlimit(RLIMIT_NOFILE, &rlim);
    return rlim.rlim_cur;
}   

如果您将所有这些内容放在一个文件中(我这样做只是为了检查它),您可以生成与此类似的输出,以确认它按照广告的方式工作:

0:     0                  O_RDWR  dup() ok
1:     0                O_WRONLY  dup() ok
2:     0                  O_RDWR  dup() ok
3:     0              O_NONBLOCK  dup() ok
4:     0     O_WRONLY O_NONBLOCK  dup() ok
5:    -1      Bad file descriptor Bad file descriptor
6:    -1      Bad file descriptor Bad file descriptor
7:    -1      Bad file descriptor Bad file descriptor
8:    -1      Bad file descriptor Bad file descriptor
9:    -1      Bad file descriptor Bad file descriptor

我希望能够回答您的任何问题,以防万一您我想知道,我实际上来这里是为了寻找OP提出的问题的答案,在阅读答案后,请记住我几年前就已经编写了代码。享受。

Here's some code I used to use, I didn't know about /proc/self (thx Donal!), but this way is probably more generic anyway. I've included the required includes for all the functions at the top.

#include <string.h>
#include <stdio.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/resource.h>

#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif

/* implementation of Donal Fellows method */ 
int get_num_fds()
{
     int fd_count;
     char buf[64];
     struct dirent *dp;

     snprintf(buf, 64, "/proc/%i/fd/", getpid());

     fd_count = 0;
     DIR *dir = opendir(buf);
     while ((dp = readdir(dir)) != NULL) {
          fd_count++;
     }
     closedir(dir);
     return fd_count;
}

I went through a very bad problem with leaking file handles once, and it turns out I actually coded the solution Tom H. suggested:

/* check whether a file-descriptor is valid */
int pth_util_fd_valid(int fd)
{
     if (fd < 3 || fd >= FD_SETSIZE)
          return FALSE;
     if (fcntl(fd, F_GETFL) == -1 && errno == EBADF)
          return FALSE;
     return TRUE;
}

/* check first 1024 (usual size of FD_SESIZE) file handles */
int test_fds()
{
     int i;
     int fd_dup;
     char errst[64];
     for (i = 0; i < FD_SETSIZE; i++) {
          *errst = 0;
          fd_dup = dup(i);
          if (fd_dup == -1) {
                strcpy(errst, strerror(errno));
                // EBADF  oldfd isn’t an open file descriptor, or newfd is out of the allowed range for file descriptors.
                // EBUSY  (Linux only) This may be returned by dup2() during a race condition with open(2) and dup().
                // EINTR  The dup2() call was interrupted by a signal; see signal(7).
                // EMFILE The process already has the maximum number of file descriptors open and tried to open a new one.
          } else {
                close(fd_dup);
                strcpy(errst, "dup() ok");
          }
          printf("%4i: %5i %24s %s\n", i, fcntl(i, F_GETOWN), fd_info(i), errst);
     }
     return 0;
}

You'll probably want these too, to satisfy the last printf above...

char *fcntl_flags(int flags)
{
    static char output[128];
    *output = 0;

    if (flags & O_RDONLY)
        strcat(output, "O_RDONLY ");
    if (flags & O_WRONLY)
        strcat(output, "O_WRONLY ");
    if (flags & O_RDWR)
        strcat(output, "O_RDWR ");
    if (flags & O_CREAT)
        strcat(output, "O_CREAT ");
    if (flags & O_EXCL)
        strcat(output, "O_EXCL ");
    if (flags & O_NOCTTY)
        strcat(output, "O_NOCTTY ");
    if (flags & O_TRUNC)
        strcat(output, "O_TRUNC ");
    if (flags & O_APPEND)
        strcat(output, "O_APPEND ");
    if (flags & O_NONBLOCK)
        strcat(output, "O_NONBLOCK ");
    if (flags & O_SYNC)
        strcat(output, "O_SYNC ");
    if (flags & O_ASYNC)
        strcat(output, "O_ASYNC ");

    return output;
}

char *fd_info(int fd)
{
    if (fd < 0 || fd >= FD_SETSIZE)
        return FALSE;
    // if (fcntl(fd, F_GETFL) == -1 && errno == EBADF)
    int rv = fcntl(fd, F_GETFL);
    return (rv == -1) ? strerror(errno) : fcntl_flags(rv);
}

FD_SETSIZE is usually 1024, and the maximum files per process is usually 1024. If you want to be sure, you can replace it with a call to this function, as described by TomH.

#include <sys/time.h>
#include <sys/resource.h>

rlim_t get_rlimit_files()
{
    struct rlimit rlim;
    getrlimit(RLIMIT_NOFILE, &rlim);
    return rlim.rlim_cur;
}   

If you put all of that together into a single file (which I did, just to check it), you can produce an output similar to this to confirm it works as advertised:

0:     0                  O_RDWR  dup() ok
1:     0                O_WRONLY  dup() ok
2:     0                  O_RDWR  dup() ok
3:     0              O_NONBLOCK  dup() ok
4:     0     O_WRONLY O_NONBLOCK  dup() ok
5:    -1      Bad file descriptor Bad file descriptor
6:    -1      Bad file descriptor Bad file descriptor
7:    -1      Bad file descriptor Bad file descriptor
8:    -1      Bad file descriptor Bad file descriptor
9:    -1      Bad file descriptor Bad file descriptor

I hope that answers any questions you have, and in case you were wondering, I actually came here looking for the answer to the question the OP asked, and upon reading the answered, remember I had already written the code years ago. Enjoy.

你的笑 2024-11-25 07:37:52

由于您使用的是 Linux,因此您(几乎可以肯定)已经安装了 /proc 文件系统。这意味着最简单的方法是获取 /proc/self/fd 的内容列表;其中的每个文件都以 FD 命名。 (当然,使用 g_dir_openg_dir_read_nameg_dir_close 来完成列表。)

否则获取信息会相当尴尬(没有有用的 POSIX API例如;这是一个没有标准化的领域)。

Since you're on Linux, you've (almost certainly) got the /proc filesystem mounted. That means that the easiest method is going to be to get a list of the contents of /proc/self/fd; each file in there is named after a FD. (Use g_dir_open, g_dir_read_name and g_dir_close to do the listing, of course.)

Getting the information otherwise is moderately awkward (there's no helpful POSIX API for example; this is an area that wasn't standardized).

呆头 2024-11-25 07:37:52

如果您可以通过 pid 识别进程,您可以简单地执行

ls -l /proc/<pid>/fd | wc - l

在 C 中,您可以管道所有内容并重用输出,或者您可以自己在上述目录中对文件进行计数(计数方法,例如此处 使用 C 计算目录中的文件数量

If you can identify the process via pid you can simply do

ls -l /proc/<pid>/fd | wc - l

In C you can pipe everything and reuse either the output or you may count the files by yourself in the above mentioned directory(count method e.g. here Counting the number of files in a directory using C)

那片花海 2024-11-25 07:37:52

有时 C++ 是一种选择,Donal 的解决方案使用 boost::filesystem:

#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <unistd.h>

namespace fs = boost::filesystem;

int main()
{
    std::string path = "/proc/" + std::to_string(::getpid()) + "/fd/";
    unsigned count = std::distance(fs::directory_iterator(path),
                                   fs::directory_iterator());
    std::cout << "Number of opened FDs: " << count << std::endl;
}

Sometimes C++ is an option, Donal's solution using boost::filesystem:

#include <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <unistd.h>

namespace fs = boost::filesystem;

int main()
{
    std::string path = "/proc/" + std::to_string(::getpid()) + "/fd/";
    unsigned count = std::distance(fs::directory_iterator(path),
                                   fs::directory_iterator());
    std::cout << "Number of opened FDs: " << count << std::endl;
}
梦在深巷 2024-11-25 07:37:52

如果您的意思是如何从进程内以编程方式执行此操作,那么正常(如果有点可怕)的方法是执行诸如循环所有可能的描述符之类的操作(使用 getrlimit() 读取 RLIMIT_NOFILE 来查找范围)对每个调用类似 fcntl(fd, F_GETFD, 0) 的内容,并检查 EBADF 响应以查看哪些未打开。

如果您的意思是您想从 shell 中找出进程打开了哪些文件,那么 lsof -p 就是您想要的。

If you mean how can you do it programatically from within the process then the normal (if slightly horrid) method is to do something like looping over all possible descriptors (use getrlimit() to read RLIMIT_NOFILE to find the range) calling something like fcntl(fd, F_GETFD, 0) on each one and checking for EBADF responses to see which ones are not open.

If you mean that you want to find out from the shell what files a process has open then lsof -p <pid> is what you want.

与风相奔跑 2024-11-25 07:37:52

fstat 命令列出了系统的所有正在运行的进程及其打开的描述符,此外它还列出了描述符的类型(文件、套接字、管道等),并尝试给出描述符正在读取或写入的内容(例如文件系统)的提示该文件系统上的索引节点号是多少

fstat command lists all running processes of the system and their open descriptors furthermore it lists what type of descriptor it is (file, socket, pipe, etc) and tries to give a hint of what the descriptor is reading or writing on such as what filesystem and what inode number on that file system

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文