diff --git a/Utils.cpp b/Utils.cpp index 5e12194..4464afc 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -753,9 +753,52 @@ bool IsRunningInEmulator() { 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& 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 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 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 0b35a7b..48a57d9 100644 --- a/Utils.h +++ b/Utils.h @@ -127,7 +127,8 @@ bool Readlinkat(int dirfd, const std::string& path, std::string* result); /* 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 WaitForFile(const char* filename, std::chrono::nanoseconds timeout);