How to check if a given file descriptor stored in a variable is still valid?

CLinuxGccFile Descriptor

C Problem Overview


I have a file descriptor stored in a variable say var. How can I check whether that descriptor is valid at a later stage?

  fdvar1= open(.....);
  fdvar2 = fdvar1;       // Please ignore the bad design

  ....
  // lots of loops , conditionals and threads. It can call close(fdvar2) also.  
  ....

  if(CheckValid(fdvar1)) // How can I do this check  ?
    write(fdvar1, ....);

Now i want to check whether var1 (which still holds the opened descriptor) is still valid. Any API's for that ?

C Solutions


Solution 1 - C

fcntl(fd, F_GETFD) is the canonical cheapest way to check that fd is a valid open file descriptor. If you need to batch-check a lot, using poll with a zero timeout and the events member set to 0 and checking for POLLNVAL in revents after it returns is more efficient.

With that said, the operation "check if a given resource handle is still valid" is almost always fundamentally incorrect. After a resource handle is freed (e.g. a fd is closed), its value may be reassigned to the next such resource you allocate. If there are any remaining references that might be used, they will wrongly operate on the new resource rather than the old one. Thus, the real answer is probably: If you don't already know by the logic of your program, you have major fundamental logic errors that need to be fixed.

Solution 2 - C

You can use the fcntl() function:

int fd_is_valid(int fd)
{
    return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}

Solution 3 - C

I don't think there is any function that can tell you if the descriptor is still valid. The descriptor is typically just a small integer like 6 and your libc can choose to reuse that number if you close the file and open a new one later.

Instead, you should consider using dup() to copy the file descriptor. By duplicating the file descriptor instead of using the same descriptor in multiple places, it might become easier for you to know whether the file descriptor is still valid. You just have to remember to close both the original descriptor and the duplicated one when you are done.

Solution 4 - C

From this forum article:

int is_valid_fd(int fd)
{
    return fcntl(fd, F_GETFL) != -1 || errno != EBADF;
}

> fcntl(GETFL) is probably the cheapest and least likely to fail > operation you can perform on a file descriptor. In particular, the > specification suggests that it cannot be interrupted by signals, nor > is it affected by any sort of lock held anywhere.

Solution 5 - C

It seems to me that if you want to know if it still points to the same resource, one (non-perfect) approach would be to fstat() the descriptor just after open and then later you can do it again and compare the results. Start by looking at .st_mode& S_IFMT and go from there -- is it a filesystem object? Look at .st_dev / .st_ino. Is it a socket? Try getsockname(), getpeername(). It won't be 100% certain, but it can tell you if it definitely isn't the same.

Solution 6 - C

i solved this problem for me. i don't know whether it can be used for general purpose but for serial connections it works fine (e.g. /dev/ttyUSB0)!

struct stat s;
fstat(m_fileDescriptor, &s);
 
// struct stat::nlink_t   st_nlink;   ... number of hard links 
if( s.st_nlink < 1 ){
 // treat device disconnected case
}

For details see e.g. man page http://linux.die.net/man/2/fstat

Cheers, Flo

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLunar MushroomsView Question on Stackoverflow
Solution 1 - CR.. GitHub STOP HELPING ICEView Answer on Stackoverflow
Solution 2 - Cuser529758View Answer on Stackoverflow
Solution 3 - CDavid GraysonView Answer on Stackoverflow
Solution 4 - CwbaoView Answer on Stackoverflow
Solution 5 - CJohn HascallView Answer on Stackoverflow
Solution 6 - CfloznView Answer on Stackoverflow