¿Encontrar descriptores de archivos abiertos para un proceso Linux (código C)?

9 minutos de lectura

Quería encontrar todos los fds abiertos para un proceso en Linux.

¿Puedo hacerlo con las funciones de la biblioteca simplista?

¿Encontrar descriptores de archivos abiertos para un proceso Linux codigo
orwellófilo

Aquí hay un código que solía usar, no sabía sobre /proc/self (¡gracias Donal!), pero esta forma es probablemente más genérica de todos modos. He incluido las inclusiones requeridas para todas las funciones en la parte superior.

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

Pasé por un problema muy grave con la fuga de identificadores de archivos una vez, y resulta que en realidad codifiqué la solución que Tom H. sugirió:

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

Probablemente querrás estos también, para satisfacer la última impresión anterior…

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 suele ser 1024, y el máximo de archivos por proceso suele ser 1024. Si quiere estar seguro, puede reemplazarlo con una llamada a esta función, como lo describe 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 junta todo eso en un solo archivo (lo cual hice, solo para verificarlo), puede producir un resultado similar a este para confirmar que funciona como se anuncia:

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

Espero que responda cualquier pregunta que tenga, y en caso de que se lo pregunte, en realidad vine aquí buscando la respuesta a la pregunta que hizo el OP, y al leer la respuesta, recuerde que ya había escrito el código hace años. Disfrutar.

  • Tenga en cuenta que pth_util_fd_valid no funcionará con huecos en la tabla fd. Considere el siguiente caso: int fd = open(...); // fd =3 fd = open(...); // fd=4 close(4) La función no alcanzará fd=4

    – kfir

    06/02/2015 a las 14:55


  • @kfir: pth_util_fd_valid solo informa la validez de un identificador de archivo dado, no contiene un bucle.

    – Orwellófilo

    14 de febrero de 2015 a las 16:24

  • El segundo ejemplo de código debe incluir sys/select.h para definir FD_SETSIZE.

    – Andrew Domaszek

    11 mayo 2017 a las 15:39

  • Sería más fácil escanear /proc/self/fd o el ligeramente más portátil /dev/fd que ensamblar un nombre de ruta basado en el ID del proceso actual.

    – David Foerster

    7 mayo 2021 a las 9:10

¿Encontrar descriptores de archivos abiertos para un proceso Linux codigo
Becarios Donal

Ya que está en Linux, tiene (casi seguro) la /proc sistema de archivos montado. Eso significa que el método más fácil será obtener una lista del contenido de /proc/self/fd; cada archivo allí tiene el nombre de un FD. (Utilizar g_dir_open, g_dir_read_name y g_dir_close para hacer la lista, por supuesto.)

De lo contrario, obtener la información es moderadamente incómodo (por ejemplo, no hay una API POSIX útil; esta es un área que no estaba estandarizada).

  • Para enumerarlos para otro proceso, enumere el directorio /proc/PID/fd en su lugar (donde PID es la identificación del proceso en cuestión). Solo podrá verlos para algunos procesos si no es root.

    – Becarios Donal

    5 de julio de 2011 a las 13:18


  • El uso de /proc/*/pid es, por supuesto, muy específico de Linux y nada portátil, pero si eso no es un problema, entonces debería funcionar bien.

    – TomH

    5 de julio de 2011 a las 13:37

  • @Tom: La pregunta era etiquetado con linux

    – Becarios Donal

    17/07/2011 a las 21:40

  • Hay un pequeño escollo en lo que se busca: el /proc/self/fd El directorio en sí mismo también cuenta como un descriptor de archivo abierto mientras lo escanea.

    – C2H5OH

    24 de enero de 2013 a las 15:08

  • @C2H5OH Sí. Pero las alternativas son terribles o igual de problemáticas (p. ej., ejecutar un subproceso para realizar el sondeo abrirá más FD).

    – Becarios Donal

    25 de enero de 2013 a las 18:03


1647533649 701 ¿Encontrar descriptores de archivos abiertos para un proceso Linux codigo
fyr

Si puede identificar el proceso a través de pid, simplemente puede hacer

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

En C, puede canalizar todo y reutilizar la salida o puede contar los archivos usted mismo en el directorio mencionado anteriormente (método de conteo, por ejemplo, aquí Contando la cantidad de archivos en un directorio usando C)

A veces, C++ es una opción, la solución de Donal usando 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;
}

Si quiere decir cómo puede hacerlo programáticamente desde dentro del proceso, entonces el método normal (aunque un poco horrible) es hacer algo como recorrer todos los descriptores posibles (use getrlimit() leer RLIMIT_NOFILE para encontrar el rango) llamando a algo como fcntl(fd, F_GETFD, 0) en cada uno y verificando las respuestas de EBADF para ver cuáles no están abiertas.

Si quiere decir que desea averiguar desde el shell qué archivos ha abierto un proceso, entonces lsof -p <pid> es lo que quieres

  • Veo una buena cantidad de procesos que tienen FD abiertos 0, 1, 2 y 255. Obtener 252 llamadas al sistema fallidas no sería agradable…

    – Becarios Donal

    5 de julio de 2011 a las 13:21

  • Todo depende: obviamente, no desea hacerlo en una pieza de código crítica para el rendimiento, pero aparte de eso, no es un gran problema. De todos modos, es más probable que el límite sea algo así como 2048 en un sistema Linux moderno.

    – TomH

    5 de julio de 2011 a las 13:36

  • RLIMIT_NOFILE solo le indica el máximo para los descriptores de archivos recién creados, no el límite de los descriptores de archivos abiertos actualmente, por lo que no puede usar getrlimit para descubrir un límite superior en los números de descriptores de archivos.

    -Richard Kettlewell

    5 de julio de 2011 a las 17:47

  • Sí, estoy tratando de hacer esto ahora como parte de un código de sandboxing. Quiero ejecutar un código de configuración arbitrario, luego enumerar todos los identificadores de archivos abiertos y cerrarlos, y luego usar setrlimit para evitar que se abran nuevos identificadores de archivos.

    – gsteff

    26 de diciembre de 2011 a las 17:18

1647533649 693 ¿Encontrar descriptores de archivos abiertos para un proceso Linux codigo
maheshgupta024

El comando fstat enumera todos los procesos en ejecución del sistema y sus descriptores abiertos; además, enumera qué tipo de descriptor es (archivo, socket, tubería, etc.) e intenta dar una pista de lo que el descriptor está leyendo o escribiendo, como en qué sistema de archivos y qué número de inodo en ese sistema de archivos

  • Veo una buena cantidad de procesos que tienen FD abiertos 0, 1, 2 y 255. Obtener 252 llamadas al sistema fallidas no sería agradable…

    – Becarios Donal

    5 de julio de 2011 a las 13:21

  • Todo depende: obviamente, no desea hacerlo en una pieza de código crítica para el rendimiento, pero aparte de eso, no es un gran problema. De todos modos, es más probable que el límite sea algo así como 2048 en un sistema Linux moderno.

    – TomH

    5 de julio de 2011 a las 13:36

  • RLIMIT_NOFILE solo le indica el máximo para los descriptores de archivos recién creados, no el límite de los descriptores de archivos abiertos actualmente, por lo que no puede usar getrlimit para descubrir un límite superior en los números de descriptores de archivos.

    -Richard Kettlewell

    5 de julio de 2011 a las 17:47

  • Sí, estoy tratando de hacer esto ahora como parte de un código de sandboxing. Quiero ejecutar un código de configuración arbitrario, luego enumerar todos los identificadores de archivos abiertos y cerrarlos, y luego usar setrlimit para evitar que se abran nuevos identificadores de archivos.

    – gsteff

    26 de diciembre de 2011 a las 17:18

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad