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

后端 未结 6 1249
遇见更好的自我
遇见更好的自我 2020-12-08 01:02

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

Can I do it with glib library functions ?

6条回答
  •  無奈伤痛
    2020-12-08 01:17

    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 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #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 
    #include 
    
    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.

提交回复
热议问题