Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What to do if a posix close call fails?

Tags:

On my system (Ubuntu Linux, glibc), man page of a close call specifies several error return values it can return. It also says

Not checking the return value of close() is a common but nevertheless serious programming error.

and at the same time

Note that the return value should only be used for diagnostics. In particular close() should not be retried after an EINTR since this may cause a reused descriptor from another thread to be closed.

So I am not allowed to ignore the return value nor to retry the call.

Given that, how shall I handle the close() call failure?

If the error happened when I was writing something to the file, I am probably supposed to try to write the information somewhere else to avoid the data loss.

If I was only reading the file, can I just log the failure and continue the program pretending nothing happened? Are there any caveats, leak of file descriptors or whatever else?

like image 406
Ilya Popov Avatar asked Oct 13 '15 23:10

Ilya Popov


People also ask

What does close return on failure?

close() returns zero on success. On error, -1 is returned, and errno is set to indicate the error.

What does close() do?

The close() function shall deallocate the file descriptor indicated by fildes. To deallocate means to make the file descriptor available for return by subsequent calls to open() or other functions that allocate file descriptors.

What is Open return failure?

It returns -1, so that call was in error.

What does close system call do?

A close system call is a system call used to close a file descriptor by the kernel. For most file systems, a program terminates access to a file in a filesystem using the close system call.


2 Answers

In practice, close should never be retried on error, and the fd you passed to close is always invalid (closed) after close returns, regardless of whether an error occurred. In some cases, an error may indicate that data was lost (certain NFS setups) or unusual hardware conditions for devices (e.g. tape could not be rewound), so you may want to be cautious to avoid data loss, but you should never attempt to close the fd again.

In theory, POSIX was unclear in the past as to whether the fd remains open when close fails with EINTR, and systems disagreed. Since it's important to know the state (otherwise you have either fd leaks or double-close bugs which are extremely dangerous in multithreaded programs), the resolution to Austin Group issue #529 specified the behavior strictly for future versions of POSIX, that EINTR means the fd remains open. This is the right behavior consistent with the definition of EINTR elsewhere, but Linux refuses to accept it. (FWIW there's an easy workaround for this that's possible at the libc syscall wrapper level; see glibc PR #14627.) Fortunately it never arises in practice anyway.

Some related questions you might find informative:

  • What are the reasons to check for error on close()?
  • Trying to make close sleep on Linux
like image 55
R.. GitHub STOP HELPING ICE Avatar answered Oct 17 '22 11:10

R.. GitHub STOP HELPING ICE


First of all: EINTR means exactly that: System call was interrupted, if this happens on a close() call, there is exactly nothing you can do.

Apart from maybe keeping track of the fact, that if the fd belonged to a file, this file is possibly corrupt, there is not much you can do about errors on close() at all - depending on the return value. AFAIK the only case, where a close can be retried is on EBUSY, but I have yet to see that.

So:

  • Not checking the result of close() might mean that you miss file corruption, especially truncation.
  • Depending on the error, most of the time you can do nothing - a failed close() just means something has gone awfully wrong outside the scope of your application.
like image 28
Eugen Rieck Avatar answered Oct 17 '22 11:10

Eugen Rieck