Merge "Add UnmountTreeWithPrefix util method." am: 2e9aafb620 am: 5e10de1301
am: 8bdc5e6de8
Change-Id: I0c3a14b70c07a6b97cb429350eda653f6fb5954a
diff --git a/Utils.cpp b/Utils.cpp
index e34e0ab..667d277 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -753,9 +753,52 @@
return android::base::GetBoolProperty("ro.kernel.qemu", false);
}
-status_t UnmountTree(const std::string& prefix) {
- if (umount2(prefix.c_str(), MNT_DETACH)) {
- PLOG(ERROR) << "Failed to unmount " << prefix;
+static status_t findMountPointsWithPrefix(const std::string& prefix,
+ std::list<std::string>& mountPoints) {
+ // Add a trailing slash if the client didn't provide one so that we don't match /foo/barbaz
+ // when the prefix is /foo/bar
+ std::string prefixWithSlash(prefix);
+ if (prefix.back() != '/') {
+ android::base::StringAppendF(&prefixWithSlash, "/");
+ }
+
+ std::unique_ptr<FILE, int (*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
+ if (!mnts) {
+ PLOG(ERROR) << "Unable to open /proc/mounts";
+ return -errno;
+ }
+
+ // Some volumes can be stacked on each other, so force unmount in
+ // reverse order to give us the best chance of success.
+ struct mntent* mnt; // getmntent returns a thread local, so it's safe.
+ while ((mnt = getmntent(mnts.get())) != nullptr) {
+ auto mountPoint = std::string(mnt->mnt_dir) + "/";
+ if (android::base::StartsWith(mountPoint, prefixWithSlash)) {
+ mountPoints.push_front(mountPoint);
+ }
+ }
+ return OK;
+}
+
+// Unmount all mountpoints that start with prefix. prefix itself doesn't need to be a mountpoint.
+status_t UnmountTreeWithPrefix(const std::string& prefix) {
+ std::list<std::string> toUnmount;
+ status_t result = findMountPointsWithPrefix(prefix, toUnmount);
+ if (result < 0) {
+ return result;
+ }
+ for (const auto& path : toUnmount) {
+ if (umount2(path.c_str(), MNT_DETACH)) {
+ PLOG(ERROR) << "Failed to unmount " << path;
+ result = -errno;
+ }
+ }
+ return result;
+}
+
+status_t UnmountTree(const std::string& mountPoint) {
+ if (umount2(mountPoint.c_str(), MNT_DETACH)) {
+ PLOG(ERROR) << "Failed to unmount " << mountPoint;
return -errno;
}
return OK;
diff --git a/Utils.h b/Utils.h
index 976d7b1..e51ec1e 100644
--- a/Utils.h
+++ b/Utils.h
@@ -127,7 +127,8 @@
/* Checks if Android is running in QEMU */
bool IsRunningInEmulator();
-status_t UnmountTree(const std::string& prefix);
+status_t UnmountTreeWithPrefix(const std::string& prefix);
+status_t UnmountTree(const std::string& mountPoint);
status_t DeleteDirContentsAndDir(const std::string& pathname);