am c7b5b570: Null-terminate readlink() result, full remount.

* commit 'c7b5b570bd05ed3bc921b0c2dc346416a52b4e3e':
  Null-terminate readlink() result, full remount.
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index e906fa7..d8d9198 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -82,7 +82,7 @@
             PLOG(ERROR) << "Failed to exec";
         }
 
-        PLOG(DEBUG) << "FUSE exiting";
+        LOG(ERROR) << "FUSE exiting";
         _exit(1);
     }
 
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index e4fdb86..29a357f 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -137,12 +137,15 @@
         initAsecStage();
     }
 
+    if (!(getMountFlags() & MountFlags::kVisible)) {
+        // Not visible to apps, so no need to spin up FUSE
+        return OK;
+    }
+
     dev_t before = GetDevice(mFuseWrite);
 
     if (!(mFusePid = fork())) {
-        if (!(getMountFlags() & MountFlags::kVisible)) {
-            // TODO: do we need to wrap this device?
-        } else if (getMountFlags() & MountFlags::kPrimary) {
+        if (getMountFlags() & MountFlags::kPrimary) {
             if (execl(kFusePath, kFusePath,
                     "-u", "1023", // AID_MEDIA_RW
                     "-g", "1023", // AID_MEDIA_RW
@@ -163,7 +166,7 @@
             }
         }
 
-        PLOG(DEBUG) << "FUSE exiting";
+        LOG(ERROR) << "FUSE exiting";
         _exit(1);
     }
 
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 6caa5c0..d1a0b2f 100755
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -481,6 +481,46 @@
     return 0;
 }
 
+static int sane_readlinkat(int dirfd, const char* path, char* buf, size_t bufsiz) {
+    ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
+    if (len < 0) {
+        return -1;
+    } else if (len == (ssize_t) bufsiz) {
+        return -1;
+    } else {
+        buf[len] = '\0';
+        return 0;
+    }
+}
+
+static int unmount_tree(const char* path) {
+    size_t path_len = strlen(path);
+
+    FILE* fp = setmntent("/proc/mounts", "r");
+    if (fp == NULL) {
+        ALOGE("Error opening /proc/mounts: %s", strerror(errno));
+        return -errno;
+    }
+
+    // Some volumes can be stacked on each other, so force unmount in
+    // reverse order to give us the best chance of success.
+    std::list<std::string> toUnmount;
+    mntent* mentry;
+    while ((mentry = getmntent(fp)) != NULL) {
+        if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
+            toUnmount.push_front(std::string(mentry->mnt_dir));
+        }
+    }
+    endmntent(fp);
+
+    for (auto path : toUnmount) {
+        if (umount2(path.c_str(), MNT_DETACH)) {
+            ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
+        }
+    }
+    return 0;
+}
+
 int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
     LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
 
@@ -499,7 +539,7 @@
     }
 
     // Figure out root namespace to compare against below
-    if (readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
+    if (sane_readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
         PLOG(ERROR) << "Failed to readlink";
         closedir(dir);
         return -1;
@@ -524,7 +564,7 @@
 
         // Matches so far, but refuse to touch if in root namespace
         LOG(DEBUG) << "Found matching PID " << de->d_name;
-        if (readlinkat(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
+        if (sane_readlinkat(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
             PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
             goto next;
         }
@@ -536,18 +576,17 @@
         // We purposefully leave the namespace open across the fork
         nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
         if (nsFd < 0) {
-            PLOG(WARNING) << "Failed to open namespace";
+            PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
             goto next;
         }
 
         if (!(child = fork())) {
             if (setns(nsFd, CLONE_NEWNS) != 0) {
-                PLOG(ERROR) << "Failed to setns";
+                PLOG(ERROR) << "Failed to setns for " << de->d_name;
                 _exit(1);
             }
 
-            // Unmount current view and replace with requested view
-            umount2("/storage", MNT_FORCE);
+            unmount_tree("/storage");
 
             std::string storageSource;
             if (mode == "default") {
@@ -562,9 +601,21 @@
             }
             if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
                     NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
-                PLOG(WARNING) << "Failed to mount " << storageSource;
-                return false;
+                PLOG(ERROR) << "Failed to mount " << storageSource << " for "
+                        << de->d_name;
+                _exit(1);
             }
+
+            // Mount user-specific symlink helper into place
+            userid_t user_id = multiuser_get_user_id(uid);
+            std::string userSource(StringPrintf("/mnt/user/%d", user_id));
+            if (TEMP_FAILURE_RETRY(mount(userSource.c_str(), "/storage/self",
+                    NULL, MS_BIND, NULL)) == -1) {
+                PLOG(ERROR) << "Failed to mount " << userSource << " for "
+                        << de->d_name;
+                _exit(1);
+            }
+
             _exit(0);
         }