Mark block device as read-only before mounting.

Mounting a block device as read-only still allows the filesystem to
write to the block device, while keeping the user-facing filesystem
interface "read-only". This behavior will make dm-verity to fail after
reboot if any block is modified during postinstall.

This patch marks the block device as read-only before mounting it, and
marks them read-only or read-write before using them during the update.

Bug: 27859604
TEST=Added logging and deployed an update to brillo, devices are marked RO/RW as needed during a delta update.

Change-Id: I781293cc0b3447dac708470ba6efad4103bf2a58
diff --git a/common/utils.cc b/common/utils.cc
index 1b718a4..49502ff 100644
--- a/common/utils.cc
+++ b/common/utils.cc
@@ -638,6 +638,30 @@
   return true;
 }
 
+bool SetBlockDeviceReadOnly(const string& device, bool read_only) {
+  int fd = HANDLE_EINTR(open(device.c_str(), O_RDONLY | O_CLOEXEC));
+  if (fd < 0) {
+    PLOG(ERROR) << "Opening block device " << device;
+    return false;
+  }
+  ScopedFdCloser fd_closer(&fd);
+  // We take no action if not needed.
+  int read_only_flag;
+  int expected_flag = read_only ? 1 : 0;
+  int rc = ioctl(fd, BLKROGET, &read_only_flag);
+  // In case of failure reading the setting we will try to set it anyway.
+  if (rc == 0 && read_only_flag == expected_flag)
+    return true;
+
+  rc = ioctl(fd, BLKROSET, &expected_flag);
+  if (rc != 0) {
+    PLOG(ERROR) << "Marking block device " << device << " as read_only="
+                << expected_flag;
+    return false;
+  }
+  return true;
+}
+
 bool MountFilesystem(const string& device,
                      const string& mountpoint,
                      unsigned long mountflags,  // NOLINT(runtime/int)