简体   繁体   English

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

[英]Finding open file descriptors for a process linux ( C code )?

I wanted to find all fds opened for a process in linux.我想找到为 linux 中的进程打开的所有 fd。

Can I do it with glib library functions?我可以使用 glib 库函数吗?

Here's some code I used to use, I didn't know about /proc/self (thx Donal,).这是我以前使用的一些代码,我不知道 /proc/self (谢谢 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:我曾经遇到过一个非常糟糕的文件句柄泄漏问题,事实证明我实际上编写了 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;
}

You'll probably want these too, to satisfy the last printf above...你可能也想要这些,以满足上面的最后一个 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 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. FD_SETSIZE 通常为 1024,每个进程的最大文件数通常为 1024。如果您想确定,可以将其替换为调用此 function,如 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:如果您将所有这些放在一个文件中(我这样做,只是为了检查它),您可以生成一个类似于此的 output 以确认它像宣传的那样工作:

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.我希望能回答您的任何问题,如果您想知道,我实际上是来这里寻找 OP 提出的问题的答案,在阅读答案后,请记住我几年前就已经编写了代码。 Enjoy.享受。

Since you're on Linux, you've (almost certainly) got the /proc filesystem mounted.由于您使用的是 Linux,因此您(几乎可以肯定)安装了/proc文件系统。 That means that the easiest method is going to be to get a list of the contents of /proc/self/fd ;这意味着最简单的方法是获取/proc/self/fd的内容列表; each file in there is named after a FD.那里的每个文件都以 FD 命名。 (Use g_dir_open , g_dir_read_name and g_dir_close to do the listing, of course.) (当然,使用g_dir_openg_dir_read_nameg_dir_close进行列表。)

Getting the information otherwise is moderately awkward (there's no helpful POSIX API for example; this is an area that wasn't standardized).否则,获取信息有点尴尬(例如,没有有用的 POSIX API;这是一个没有标准化的领域)。

If you can identify the process via pid you can simply do如果您可以通过 pid 识别进程,您可以简单地执行

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 eg here Counting the number of files in a directory using C ) 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 eg here Counting the number of files in a directory using C )

Sometimes C++ is an option, Donal's solution using boost::filesystem:有时 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;
}

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

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.如果您的意思是要从 shell 中找出进程打开了哪些文件,那么lsof -p <pid>就是您想要的。

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 fstat 命令列出了系统的所有正在运行的进程及其打开的描述符,此外它还列出了它是什么类型的描述符(文件、套接字、pipe 等)并尝试提示描述符正在读取或写入的内容,例如文件系统以及该文件系统上的 inode 编号

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM