Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

Can I do it with glib library functions ?

like image 346
Ashish Avatar asked Jul 05 '11 13:07

Ashish


People also ask

How do I find file descriptors in Linux?

Use the ulimit -n command to view the number of file descriptors configured for your Linux system.

How do I find the file descriptors of a process?

You can use /proc file system or the lsof command to find all the file descriptors used by a process.

How can I tell if file descriptor is open?

In the /proc pseudo filesystem, we can find the open file descriptors under /proc/<pid>/fd/ where <pid> is the PID of a given process. Thus, we have to determine the process identification number (PID) of a process to look at its open file descriptors.


1 Answers

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 <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:

/* 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 <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:

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.

like image 179
Orwellophile Avatar answered Oct 08 '22 13:10

Orwellophile