diff --git a/src/ChunkedIO.cc b/src/ChunkedIO.cc index f5bcb4b7c1..2c766c7eb1 100644 --- a/src/ChunkedIO.cc +++ b/src/ChunkedIO.cc @@ -76,7 +76,7 @@ void ChunkedIO::DumpDebugData(const char* basefnname, bool want_reads) ChunkedIOFd io(fd, "dump-file"); io.Write(*i); io.Flush(); - close(fd); + safe_close(fd); } l->clear(); @@ -127,7 +127,7 @@ ChunkedIOFd::~ChunkedIOFd() delete [] read_buffer; delete [] write_buffer; - close(fd); + safe_close(fd); if ( partial ) { @@ -686,7 +686,7 @@ ChunkedIOSSL::~ChunkedIOSSL() ssl = 0; } - close(socket); + safe_close(socket); } diff --git a/src/FlowSrc.cc b/src/FlowSrc.cc index fe6998ea79..59ce3fd6a4 100644 --- a/src/FlowSrc.cc +++ b/src/FlowSrc.cc @@ -58,7 +58,7 @@ void FlowSrc::Process() void FlowSrc::Close() { - close(selectable_fd); + safe_close(selectable_fd); } diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 7ed8b9318e..4e9ccb7dd2 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -647,7 +647,7 @@ void RemoteSerializer::Fork() exit(1); // FIXME: Better way to handle this? } - close(pipe[1]); + safe_close(pipe[1]); return; } @@ -664,12 +664,12 @@ void RemoteSerializer::Fork() } child.SetParentIO(io); - close(pipe[0]); + safe_close(pipe[0]); // Close file descriptors. - close(0); - close(1); - close(2); + safe_close(0); + safe_close(1); + safe_close(2); // Be nice. setpriority(PRIO_PROCESS, 0, 5); @@ -4001,7 +4001,7 @@ bool SocketComm::Connect(Peer* peer) if ( connect(sockfd, res->ai_addr, res->ai_addrlen) < 0 ) { Error(fmt("connect failed: %s", strerror(errno)), peer); - close(sockfd); + safe_close(sockfd); sockfd = -1; continue; } @@ -4174,16 +4174,18 @@ bool SocketComm::Listen() { Error(fmt("can't bind to %s:%s, %s", l_addr_str.c_str(), port_str, strerror(errno))); - close(fd); if ( errno == EADDRINUSE ) { // Abandon completely this attempt to set up listening sockets, // try again later. + safe_close(fd); CloseListenFDs(); listen_next_try = time(0) + bind_retry_interval; return false; } + + safe_close(fd); continue; } @@ -4191,7 +4193,7 @@ bool SocketComm::Listen() { Error(fmt("can't listen on %s:%s, %s", l_addr_str.c_str(), port_str, strerror(errno))); - close(fd); + safe_close(fd); continue; } @@ -4227,7 +4229,7 @@ bool SocketComm::AcceptConnection(int fd) { Error(fmt("accept fail, unknown address family %d", client.ss.ss_family)); - close(clientfd); + safe_close(clientfd); return false; } @@ -4298,7 +4300,7 @@ const char* SocketComm::MakeLogString(const char* msg, Peer* peer) void SocketComm::CloseListenFDs() { for ( size_t i = 0; i < listen_fds.size(); ++i ) - close(listen_fds[i]); + safe_close(listen_fds[i]); listen_fds.clear(); } diff --git a/src/Serializer.cc b/src/Serializer.cc index 97ee8f743c..fc6d00d06c 100644 --- a/src/Serializer.cc +++ b/src/Serializer.cc @@ -746,7 +746,7 @@ FileSerializer::~FileSerializer() if ( io ) delete io; // destructor will call close() on fd else if ( fd >= 0 ) - close(fd); + safe_close(fd); } bool FileSerializer::Open(const char* file, bool pure) @@ -810,7 +810,7 @@ void FileSerializer::CloseFile() io->Flush(); if ( fd >= 0 && ! io ) // destructor of io calls close() on fd - close(fd); + safe_close(fd); fd = -1; delete [] file; diff --git a/src/logging/writers/Ascii.cc b/src/logging/writers/Ascii.cc index 4d2f59ea72..0ccdd1f569 100644 --- a/src/logging/writers/Ascii.cc +++ b/src/logging/writers/Ascii.cc @@ -86,7 +86,7 @@ void Ascii::CloseFile(double t) WriteHeaderField("end", ts); } - close(fd); + safe_close(fd); fd = 0; } diff --git a/src/util.cc b/src/util.cc index be560928d6..171fcdce37 100644 --- a/src/util.cc +++ b/src/util.cc @@ -722,7 +722,7 @@ void init_random_seed(uint32 seed, const char* read_file, const char* write_file { int amt = read(fd, buf + pos, sizeof(uint32) * (bufsiz - pos)); - close(fd); + safe_close(fd); if ( amt > 0 ) pos += amt / sizeof(uint32); @@ -1204,7 +1204,7 @@ void _set_processing_status(const char* status) len -= n; } - close(fd); + safe_close(fd); errno = old_errno; } @@ -1353,6 +1353,29 @@ bool safe_write(int fd, const char* data, int len) return true; } +void safe_close(int fd) + { + /* + * Failure cases of close(2) are ... + * EBADF: Indicative of programming logic error that needs to be fixed, we + * should always be attempting to close a valid file descriptor. + * EINTR: Ignore signal interruptions, most implementations will actually + * reclaim the open descriptor and POSIX standard doesn't leave many + * options by declaring the state of the descriptor as "unspecified". + * Attempting to inspect actual state or re-attempt close() is not + * thread safe. + * EIO: Again the state of descriptor is "unspecified", but don't recover + * from an I/O error, safe_write() won't either. + */ + if ( close(fd) < 0 && errno != EINTR ) + { + char buf[128]; + strerror_r(errno, buf, sizeof(buf)); + fprintf(stderr, "safe_close error %d: %s\n", errno, buf); + abort(); + } + } + void out_of_memory(const char* where) { reporter->FatalError("out of memory in %s.\n", where); diff --git a/src/util.h b/src/util.h index 5d1bdf188a..e69167abce 100644 --- a/src/util.h +++ b/src/util.h @@ -297,6 +297,9 @@ inline size_t pad_size(size_t size) // thread-safe as long as no two threads write to the same descriptor. extern bool safe_write(int fd, const char* data, int len); +// Wraps close(2) to emit error messages and abort on unrecoverable errors. +extern void safe_close(int fd); + extern void out_of_memory(const char* where); inline void* safe_realloc(void* ptr, size_t size)