How do I find the file handles that my process has opened in Linux?

423

Solution 1

If the libraries are opening files you don't know about, how do you know they don't need them after a fork? Unexported handles are an internal library detail, if the library wants them closed it will register an atfork() handler to close them. Walking around behind some piece of code closing its file handles behind its back will lead to subtle hard to debug problems since the library will error unexpectedly when it attempts to work with a handle it knows it opened correctly, but did not close.

Solution 2

In Linux you can check /proc/<pid>/fd directory - for every open fd there will be a file, named as handle. I'm almost sure this way is non-portable.

Alternatively you can use lsof - available for Linux, AIX, FreeBSD and NetBSD, according to man lsof.

Solution 3

You can do from a shell:

lsof -P -n -p _PID_

Where PID is your process pid.

Solution 4

As mentioned on @Louis Gerbarg's answer, the libraries are probably expecting the file handles to be kept open on fork() (which is supposed to be, after all, an almost identical copy of the parent process).

The problem most people have is on the exec() which often follows the fork(). Here, the correct solution is for the library which created the handles to mark them as close-on-exec (FD_CLOEXEC).

On libraries used by multithread programs, there is a race condition between a library creating a file handle and setting FD_CLOEXEC on it (another thread can fork() between both operations). To fix that problem, O_CLOEXEC was introduced in the Linux kernel.

Solution 5

To start with, you don't really need to care a whole lot about the open file descriptors you don't know about. If you know you're not going to write to them again, closing them is a good idea and doesn't hurt - you just did a fork() after all, the fds are open twice. But likewise, if you leave them open , they won't bother you either - after all, you don't know about them, you presumably won't be randomly writing to them.

As for what your third-party libraries will do, it's a bit of a toss-up either way. Some probably don't expect to run into a situation with a fork(), and might end up accidentally writing to the same fd from two processes without any synchronization. Others probably don't expect to have you closing their fds on them. You'll have to check. This is why it's a bad idea to randomly open a file descriptor in a library and not give it to the caller to manage.

All that said, in the spirit of answering the original question, there isn't a particularly good way. You can call dup() or dup2() on a file descriptor; if it's closed, the call will fail with EBADF. So you can say:

int newfd = dup(oldfd);
if (newfd > 0)
{
    close(newfd);
    close(oldfd);
}

but at that point you're just as well off saying close(oldfd) in the first place and ignoring any EBADFs.

Assuming you still want to take the nuclear option of closing everything, you then need to find the maximum number of open file descriptors possible. Assuming 1 to 65,535 is not a good idea. First of all, fds start at 0, of course, but also there's no particular upper limit defined. To be portable, POSIX's sysconf(_SC_OPEN_MAX) should tell you, on any sane POSIX system, though strictly speaking it's optional. If you're feeling paranoid, check the return value for -1, though at that point you mostly have to fall back on a hardcoded value anyway (1024 should be fine unless you're doing something extremely weird). Or if you're fine with being Linux-specific, you can dig around in /proc.

Don't forget to not close fds 0, 1, and 2 - that can really confuse things.

Share:
423
Alfonso Garcia-Caro
Author by

Alfonso Garcia-Caro

Updated on August 01, 2022

Comments

  • Alfonso Garcia-Caro
    Alfonso Garcia-Caro almost 2 years

    First of all, I know almost nothing of C++ so please bear with me here.

    I'm building a Windows 8 app with C#/XAML (for compatibility with the older devices, I'm not targeting Windows 8.1) and I've been given by the client the sources of a C++ library (header and source files, I mean) to decrypt datain a proprietary format. This library has been used in the iOS version of the app.

    As per this question I understand that I should compile the C++ files targeting the Windows Runtime and then use P/Invoke to call the functions I need. I've been researching and tried to follow several guides with no success: like this. this or this. In the last case I couldn't find the cl.exe compiler even if I have both VS 2012 and 2013 installed in my system.

    So, is there a dummy-safe way to compile external C++ sources to use them from a C#/XAML Windows 8 app?

    Thanks a lot in advance for your help!

    • Peter Duniho
      Peter Duniho over 9 years
      "Dummy-safe"? Probably not. There are a number of "gotchas" when trying to mix managed and unmanaged code. Per the research you've done already, you do need to make sure you're using the latest version of VS and targeting the right CRT DLLs. Also note that you need to compile for the right processor. IMHO, it would be better if you could convert the C++ code to C++/CLI (i.e. mixed-mode managed C++). Then your C++ is compiled to a managed assembly which you can use like any other managed assembly.
    • Alfonso Garcia-Caro
      Alfonso Garcia-Caro over 9 years
      Thanks for your comment! You're right, there seems to be no easy way (as I naively thought at the beginning) to use the C++ library as is. Also, the problem with VS2013 is it targets Windows 8.1 not Windows 8. Anyway, I tried to dive into the code and saw that it uses file handles which are not allowed in the Windows Runtime so I'll follow your advice and reimplement the parts I need in C# (I don't know C++/CLI very well). Luckily, it seems it's not that much at the end. Thanks again!
  • philant
    philant over 15 years
    Well, generally you don't care until you reach the limy and start getting too many open files errors.
  • Jason Coco
    Jason Coco over 15 years
    You can use the getdtablesize(2) call to get the number of entries in the process's file descriptor table.
  • Superole
    Superole over 12 years
    @sep: this answer is maybe not the best when considering the description of your problem, but it sure nails the actual question. So, thank you Felipe for helping me find the handles of my process :)