Trouver des descripteurs de fichiers ouverts pour un processus linux (code C?

je voulais trouver tous les fds ouverts pour un processus sous linux.

puis-je le faire avec des fonctions de bibliothèque glib ?

22
demandé sur Ashish 2011-07-05 17:08:54

6 réponses

puisque vous êtes sous Linux, vous avez (presque certainement) le système de fichiers /proc monté. Cela signifie que la méthode la plus simple pour obtenir une liste du contenu de /proc/self/fd ; chaque fichier, il y est nommé d'après un FD. (Utilisez g_dir_open , g_dir_read_name et g_dir_close pour faire la liste, bien sûr.)

obtenir l'information autrement est plutôt embarrassant (il n'y a pas d'API POSIX utile par exemple; c'est un domaine qui n'a pas été standardisé).

23
répondu Donal Fellows 2011-07-05 13:24:25

voici un code que j'utilisais, Je ne connaissais pas /proc/self (thx Donal!), mais cette façon est probablement plus générique de toute façon. J'ai inclus les inclusions nécessaires pour toutes les fonctions au sommet.

#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;
}

J'ai eu une fois un très mauvais problème avec la fuite des poignées de fichiers, et il s'avère que J'ai en fait codé la solution que Tom H. a suggérée:

/* 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;
}

vous voudrez probablement ceux-ci aussi, pour satisfaire le dernier printf ci-dessus...

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 est habituellement 1024, et le maximum de fichiers par processus est généralement 1024. Si vous voulez être sûr, vous pouvez le remplacer par un appel à cette fonction, comme décrit par 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;
}   

si vous regroupez tout cela dans un seul fichier (ce que j'ai fait, juste pour le vérifier), vous pouvez produire une sortie similaire à celle-ci pour confirmer que cela fonctionne comme annoncé:

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

j'espère que les réponses à toutes les questions vous avez, et au cas où vous vous demandiez, je suis effectivement venu ici à la recherche de la réponse à la question posée par L'OP, et à la lecture de la réponse, rappelez-vous que j'avais déjà écrit le code il y a des années. Profiter.

24
répondu Orwellophile 2016-07-01 10:23:01

Si vous pouvez identifier le processus par pid, vous pouvez simplement faire

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

en C vous pouvez tout pipe et réutiliser soit la sortie ou vous pouvez compter les fichiers par vous-même dans le répertoire mentionné ci-dessus(méthode de compte par exemple ici compter le nombre de fichiers dans un répertoire en utilisant C )

6
répondu fyr 2017-05-23 10:31:27

parfois C++ est une option, solution de Donal utilisant 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;
}
3
répondu Janek Olszak 2014-10-31 10:33:23

si vous voulez dire comment pouvez-vous le faire programmatiquement à partir de l'intérieur du processus alors la méthode normale (si légèrement horrible) est de faire quelque chose comme la boucle sur tous les descripteurs possibles (utilisez getrlimit() pour lire RLIMIT_NOFILE pour trouver la gamme) appelant quelque chose comme fcntl(fd, F_GETFD, 0) sur chacun d'eux et de vérifier les réponses EBADF pour voir ceux qui ne sont pas ouverts.

si vous voulez dire que vous voulez savoir à partir du shell quels fichiers un processus a ouvert alors lsof -p <pid> est ce que vous voulez.

2
répondu TomH 2011-07-05 13:17:08

la commande fstat liste tous les processus en cours d'exécution du système et leurs descripteurs ouverts. de plus, elle Liste quel type de descripteur il s'agit (fichier, socket, pipe, etc.) et tente de donner une indication de ce que le descripteur lit ou écrit sur tel ou tel système de fichiers et quel numéro d'inode sur tel ou tel système de fichiers."

1
répondu maheshgupta024 2011-07-05 13:20:14