A file descriptor closer that uses HANDLE_EINTR.

- A new flavor of ScopedFdCloser which wraps close() with HANDLE_EINTR,
  which will retry closing the file descriptor if the last close attempt
  was interrupted by EINTR. This appears to be a recommended practice
  per POSIX documentation.

- Both ScopedFdCloser and ScopedEintrSafeFdCloser ensure a successful
  close() prior to resetting the file descriptor.

- Better use of HANDLE_EINTR elsewhere: just realized that this macro
  returns the value of the last evaluation of its argument.

BUG=chromium-os:25397
TEST=Image builds properly; GPIO functionality works (x86-alex).

Change-Id: I3425bb580499c7138cd31917011662d33ffab8a6
Reviewed-on: https://gerrit.chromium.org/gerrit/17079
Reviewed-by: Andrew de los Reyes <adlr@chromium.org>
Reviewed-by: Darin Petkov <petkov@chromium.org>
Commit-Ready: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
diff --git a/update_attempter.cc b/update_attempter.cc
index 210e78a..bdf0105 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -760,20 +760,18 @@
 
   // Open device for reading.
   string dutflaga_value_dev_name = dutflaga_dev_name + "/value";
-  int dutflaga_fd;
-  HANDLE_EINTR((dutflaga_fd = open(dutflaga_value_dev_name.c_str(), 0)));
+  int dutflaga_fd = HANDLE_EINTR(open(dutflaga_value_dev_name.c_str(), 0));
   if (dutflaga_fd < 0) {
     PLOG(ERROR) << "opening dutflaga GPIO device file failed";
     return false;
   }
-  ScopedFdCloser dutflaga_fd_closer(&dutflaga_fd);
+  ScopedEintrSafeFdCloser dutflaga_fd_closer(&dutflaga_fd);
 
   // Read the dut_flaga GPIO signal. We attempt to read more than---but expect
   // to receive exactly---two characters: a '0' or '1', and a newline. This is
   // to ensure that the GPIO device returns a legible result.
   char buf[3];
-  int ret;
-  HANDLE_EINTR((ret = read(dutflaga_fd, buf, 3)));
+  int ret = HANDLE_EINTR(read(dutflaga_fd, buf, 3));
   if (ret != 2) {
     if (ret < 0)
       PLOG(ERROR) << "reading dutflaga GPIO status failed";
diff --git a/utils.h b/utils.h
index b0b28a8..728d992 100644
--- a/utils.h
+++ b/utils.h
@@ -12,6 +12,7 @@
 #include <string>
 #include <vector>
 
+#include <base/eintr_wrapper.h>
 #include <ext2fs/ext2fs.h>
 #include <glib.h>
 
@@ -276,8 +277,8 @@
   explicit ScopedFdCloser(int* fd) : fd_(fd), should_close_(true) {}
   ~ScopedFdCloser() {
     if (should_close_ && fd_ && (*fd_ >= 0)) {
-      close(*fd_);
-      *fd_ = -1;
+      if (!close(*fd_))
+        *fd_ = -1;
     }
   }
   void set_should_close(bool should_close) { should_close_ = should_close; }
@@ -287,6 +288,23 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedFdCloser);
 };
 
+// An EINTR-immune file descriptor closer.
+class ScopedEintrSafeFdCloser {
+ public:
+  explicit ScopedEintrSafeFdCloser(int* fd) : fd_(fd), should_close_(true) {}
+  ~ScopedEintrSafeFdCloser() {
+    if (should_close_ && fd_ && (*fd_ >= 0)) {
+      if (!HANDLE_EINTR(close(*fd_)))
+        *fd_ = -1;
+    }
+  }
+  void set_should_close(bool should_close) { should_close_ = should_close; }
+ private:
+  int* fd_;
+  bool should_close_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedEintrSafeFdCloser);
+};
+
 // Utility class to close a file system
 class ScopedExt2fsCloser {
  public: