web-dev-qa-db-ja.com

プロセスLinux(Cコード)のオープンファイル記述子を見つけるには?

Linuxでプロセス用に開かれたすべてのfdsを見つけたかったのです。

Glibライブラリ関数でそれを行うことはできますか?

26
Ashish

Linuxを使用しているので、(ほぼ確実に)/procファイルシステムがマウントされています。つまり、最も簡単な方法は、/proc/self/fdの内容のリストを取得することです。そこにある各ファイルは、FDにちなんで名付けられています。 (もちろん、リストを行うにはg_dir_openg_dir_read_nameおよびg_dir_closeを使用してください。)

それ以外の場合、情報を取得するのは少し厄介です(たとえば、役立つPOSIX APIはありません。これは、標準化されていない領域です)。

26
Donal Fellows

ここに私が使用していたいくつかのコードがありますが、/ proc/self(thx 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;
}

ファイルハンドルのリークに関する非常に悪い問題を1回経験しましたが、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;
}   

これらすべてを1つのファイルにまとめると(私が確認したところ、これを行いました)、次のような出力を生成して、宣伝どおりに機能することを確認できます。

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が尋ねた質問への回答を探してここに来ました。楽しい。

27
Orwellophile

Pidを介してプロセスを識別できる場合は、簡単に行うことができます

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

Cではすべてをパイプして出力を再利用するか、上記のディレクトリで自分でファイルを数えることができます(countメソッド、たとえばここでは Cを使用してディレクトリ内のファイル数を数える

6
fyr

時々C++がオプションである、Boost :: filesystemを使用するDonalのソリューション:

#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;
}
3
Janek Olszak

プロセス内からプログラムでそれをどのように行うことができるかを意味する場合、通常の(やや恐ろしい場合)メソッドは、可能なすべての記述子をループするようなものを実行します(getrlimit()を使用して_RLIMIT_NOFILE_を読み取り、範囲)それぞれに対してfcntl(fd, F_GETFD, 0)のようなものを呼び出し、EBADF応答をチェックして、開いていない応答を確認します。

シェルからプロセスが開いているファイルを確認したい場合は、_lsof -p <pid>_が適切です。

2
TomH

fstatコマンドは、システムで実行中のすべてのプロセスとそれらの開いている記述子を一覧表示し、さらに、それがどの種類の記述子(ファイル、ソケット、パイプなど)であるかを一覧表示し、どのファイルシステムなど、記述子が読み書きしているのかについてのヒントを提供しようとしますそしてそのファイルシステムのどのiノード番号

1
maheshgupta024