merge in oc-release history after reset to master
diff --git a/common/utils.cc b/common/utils.cc
index 1cb37e5..ea748c1 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -703,6 +703,32 @@
return true;
}
+bool IsMountpoint(const std::string& mountpoint) {
+ struct stat stdir, stparent;
+
+ // Check whether the passed mountpoint is a directory and the /.. is in the
+ // same device or not. If mountpoint/.. is in a different device it means that
+ // there is a filesystem mounted there. If it is not, but they both point to
+ // the same inode it basically is the special case of /.. pointing to /. This
+ // test doesn't play well with bind mount but that's out of the scope of what
+ // we want to detect here.
+ if (lstat(mountpoint.c_str(), &stdir) != 0) {
+ PLOG(ERROR) << "Error stat'ing " << mountpoint;
+ return false;
+ }
+ if (!S_ISDIR(stdir.st_mode))
+ return false;
+
+ base::FilePath parent(mountpoint);
+ parent = parent.Append("..");
+ if (lstat(parent.value().c_str(), &stparent) != 0) {
+ PLOG(ERROR) << "Error stat'ing " << parent.value();
+ return false;
+ }
+ return S_ISDIR(stparent.st_mode) &&
+ (stparent.st_dev != stdir.st_dev || stparent.st_ino == stdir.st_ino);
+}
+
// Tries to parse the header of an ELF file to obtain a human-readable
// description of it on the |output| string.
static bool GetFileFormatELF(const uint8_t* buffer, size_t size,
diff --git a/common/utils.h b/common/utils.h
index d551b7b..8cccc24 100644
--- a/common/utils.h
+++ b/common/utils.h
@@ -192,6 +192,12 @@
const std::string& fs_mount_options);
bool UnmountFilesystem(const std::string& mountpoint);
+// Return whether the passed |mountpoint| path is a directory where a filesystem
+// is mounted. Due to detection mechanism limitations, when used on directories
+// where another part of the tree was bind mounted returns true only if bind
+// mounted on top of a different filesystem (not inside the same filesystem).
+bool IsMountpoint(const std::string& mountpoint);
+
// Returns a human-readable string with the file format based on magic constants
// on the header of the file.
std::string GetFileFormat(const std::string& path);
diff --git a/common/utils_unittest.cc b/common/utils_unittest.cc
index 7852910..6e9a911 100644
--- a/common/utils_unittest.cc
+++ b/common/utils_unittest.cc
@@ -478,17 +478,37 @@
test_utils::ScopedLoopbackDeviceBinder loop_binder(
tmp_image, true, &loop_dev);
+ EXPECT_FALSE(utils::IsMountpoint(mnt_dir.path().value()));
// This is the actual test part. While we hold a file descriptor open for the
// mounted filesystem, umount should still succeed.
EXPECT_TRUE(utils::MountFilesystem(
loop_dev, mnt_dir.path().value(), MS_RDONLY, "ext4", ""));
+ // Verify the directory is a mount point now.
+ EXPECT_TRUE(utils::IsMountpoint(mnt_dir.path().value()));
+
string target_file = mnt_dir.path().Append("empty-file").value();
int fd = HANDLE_EINTR(open(target_file.c_str(), O_RDONLY));
EXPECT_GE(fd, 0);
EXPECT_TRUE(utils::UnmountFilesystem(mnt_dir.path().value()));
+ // The filesystem should be already unmounted at this point.
+ EXPECT_FALSE(utils::IsMountpoint(mnt_dir.path().value()));
IGNORE_EINTR(close(fd));
// The filesystem was already unmounted so this call should fail.
EXPECT_FALSE(utils::UnmountFilesystem(mnt_dir.path().value()));
}
+TEST(UtilsTest, IsMountpointTest) {
+ EXPECT_TRUE(utils::IsMountpoint("/"));
+ EXPECT_FALSE(utils::IsMountpoint("/path/to/nowhere"));
+
+ base::ScopedTempDir mnt_dir;
+ EXPECT_TRUE(mnt_dir.CreateUniqueTempDir());
+ EXPECT_FALSE(utils::IsMountpoint(mnt_dir.path().value()));
+
+ base::FilePath file;
+ EXPECT_TRUE(base::CreateTemporaryFile(&file));
+ ScopedPathUnlinker unlinker(file.value());
+ EXPECT_FALSE(utils::IsMountpoint(file.value()));
+}
+
} // namespace chromeos_update_engine
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index a1b6f25..11eec34 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -118,6 +118,13 @@
fs_mount_dir_ = temp_dir.value();
#endif // __ANDROID__
+ // Double check that the fs_mount_dir is not busy with a previous mounted
+ // filesystem from a previous crashed postinstall step.
+ if (utils::IsMountpoint(fs_mount_dir_)) {
+ LOG(INFO) << "Found previously mounted filesystem at " << fs_mount_dir_;
+ utils::UnmountFilesystem(fs_mount_dir_);
+ }
+
base::FilePath postinstall_path(partition.postinstall_path);
if (postinstall_path.IsAbsolute()) {
LOG(ERROR) << "Invalid absolute path passed to postinstall, use a relative"