update_engine: Attempt to mount the ROOTFS as squashfs during postinst.

This patch extends utils::MountFilesystem() to attempt to mount
the device as ext3, ext2 and squashfs before failing.

BUG=chromium:432016
TEST=None

Change-Id: Ibad2f359968d7abe9f82f11c895cac95130d73c5
Reviewed-on: https://chromium-review.googlesource.com/229020
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/postinstall_runner_action.cc b/postinstall_runner_action.cc
index 81e546e..b619cce 100644
--- a/postinstall_runner_action.cc
+++ b/postinstall_runner_action.cc
@@ -38,27 +38,8 @@
                                            &temp_rootfs_dir_));
   ScopedDirRemover temp_dir_remover(temp_rootfs_dir_);
 
-  unsigned long mountflags = MS_RDONLY;  // NOLINT(runtime/int)
-  int rc = mount(install_device.c_str(),
-                 temp_rootfs_dir_.c_str(),
-                 "ext2",
-                 mountflags,
-                 nullptr);
-  // TODO(sosa): Remove once crbug.com/208022 is resolved.
-  if (rc < 0) {
-    LOG(INFO) << "Failed to mount install part "
-              << install_device << " as ext2. Trying ext3.";
-    rc = mount(install_device.c_str(),
-               temp_rootfs_dir_.c_str(),
-               "ext3",
-               mountflags,
-               nullptr);
-  }
-  if (rc < 0) {
-    LOG(ERROR) << "Unable to mount destination device " << install_device
-               << " onto " << temp_rootfs_dir_;
+  if (!utils::MountFilesystem(install_device, temp_rootfs_dir_, MS_RDONLY))
     return;
-  }
 
   temp_dir_remover.set_should_remove(false);
   completer.set_should_complete(false);
diff --git a/utils.cc b/utils.cc
index 99a02d3..f0bf6f7 100644
--- a/utils.cc
+++ b/utils.cc
@@ -625,15 +625,19 @@
 bool MountFilesystem(const string& device,
                      const string& mountpoint,
                      unsigned long mountflags) {  // NOLINT(runtime/int)
-  int rc = mount(device.c_str(), mountpoint.c_str(), "ext3", mountflags,
-                 nullptr);
-  if (rc < 0) {
-    string msg = ErrnoNumberAsString(errno);
-    LOG(ERROR) << "Unable to mount destination device: " << msg << ". "
-               << device << " on " << mountpoint;
-    return false;
+  // TODO(sosa): Remove "ext3" once crbug.com/208022 is resolved.
+  const vector<const char*> fstypes{"ext2", "ext3", "squashfs"};
+  for (const char* fstype : fstypes) {
+    int rc = mount(device.c_str(), mountpoint.c_str(), fstype, mountflags,
+                   nullptr);
+    if (rc == 0)
+      return true;
+
+    PLOG(WARNING) << "Unable to mount destination device " << device
+                  << " on " << mountpoint << " as " << fstype;
   }
-  return true;
+  LOG(ERROR) << "Unable to mount " << device << " with any supported type";
+  return false;
 }
 
 bool UnmountFilesystem(const string& mountpoint) {
diff --git a/utils.h b/utils.h
index 56bd22e..2c0af3e 100644
--- a/utils.h
+++ b/utils.h
@@ -185,7 +185,8 @@
 bool IsRemovableDevice(const std::string& device);
 
 // Synchronously mount or unmount a filesystem. Return true on success.
-// Mounts as ext3 with default options.
+// When mounting, it will attempt to mount the the device as "ext3", "ext2" and
+// "squashfs", with the passed |flags| options.
 bool MountFilesystem(const std::string& device, const std::string& mountpoint,
                      unsigned long flags);  // NOLINT(runtime/int)
 bool UnmountFilesystem(const std::string& mountpoint);