Wrap system calls in TEMP_FAILURE_RETRY.

fs_prepare_dir() is used heavily during Zygote init, and can easily
run into EINTR.

Bug: 7151474
Change-Id: I7aac43a43483d55db47ca20456fff68ce51bbc46
diff --git a/include/cutils/fs.h b/include/cutils/fs.h
index 04c8839..fd5296b 100644
--- a/include/cutils/fs.h
+++ b/include/cutils/fs.h
@@ -19,6 +19,21 @@
 
 #include <sys/types.h>
 
+/*
+ * TEMP_FAILURE_RETRY is defined by some, but not all, versions of
+ * <unistd.h>. (Alas, it is not as standard as we'd hoped!) So, if it's
+ * not already defined, then define it here.
+ */
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({         \
+    typeof (exp) _rc;                      \
+    do {                                   \
+        _rc = (exp);                       \
+    } while (_rc == -1 && errno == EINTR); \
+    _rc; })
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/libcutils/fs.c b/libcutils/fs.c
index 1788eca..6508b67 100644
--- a/libcutils/fs.c
+++ b/libcutils/fs.c
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "cutils"
+
 #include <cutils/fs.h>
 #include <cutils/log.h>
 
@@ -31,11 +33,11 @@
 int fs_prepare_dir(const char* path, mode_t mode, uid_t uid, gid_t gid) {
     // Check if path needs to be created
     struct stat sb;
-    if (lstat(path, &sb) == -1) {
+    if (TEMP_FAILURE_RETRY(lstat(path, &sb)) == -1) {
         if (errno == ENOENT) {
             goto create;
         } else {
-            ALOGE("Failed to stat(%s): %s", path, strerror(errno));
+            ALOGE("Failed to lstat(%s): %s", path, strerror(errno));
             return -1;
         }
     }
@@ -52,17 +54,17 @@
     }
 
 create:
-    if (mkdir(path, mode) == -1) {
+    if (TEMP_FAILURE_RETRY(mkdir(path, mode)) == -1) {
         ALOGE("Failed to mkdir(%s): %s", path, strerror(errno));
         return -1;
     }
 
 fixup:
-    if (chmod(path, mode) == -1) {
-        ALOGE("Failed to chown(%s, %d): %s", path, mode, strerror(errno));
+    if (TEMP_FAILURE_RETRY(chmod(path, mode)) == -1) {
+        ALOGE("Failed to chmod(%s, %d): %s", path, mode, strerror(errno));
         return -1;
     }
-    if (chown(path, uid, gid) == -1) {
+    if (TEMP_FAILURE_RETRY(chown(path, uid, gid)) == -1) {
         ALOGE("Failed to chown(%s, %d, %d): %s", path, uid, gid, strerror(errno));
         return -1;
     }