Mount system as read-only by default

Mounting system as rw can prevent future OTA updates. The purpose
of this patch set is to prevent TWRP from mounting sytem as rw on
the first boot. Device maintainers should update their twrp.fstab
files on these devices to include an additional line:
/system_image emmc /dev/block/../system

This line will allow TWRP to create a raw system image backup to
ensure that the user can return to an original state for future
OTA updates.

Change-Id: I8929d85bc3a5b96cc564bc7f734b58d5612ec833
diff --git a/partition.cpp b/partition.cpp
index 248ee9b..2f9f41a 100644
--- a/partition.cpp
+++ b/partition.cpp
@@ -155,6 +155,7 @@
 	Crypto_Key_Location = "footer";
 	MTP_Storage_ID = 0;
 	Can_Flash_Img = false;
+	Mount_Read_Only = false;
 }
 
 TWPartition::~TWPartition(void) {
@@ -258,6 +259,7 @@
 			Storage_Name = Display_Name;
 			Wipe_Available_in_GUI = true;
 			Can_Be_Backed_Up = true;
+			Mount_Read_Only = true;
 		} else if (Mount_Point == "/data") {
 			UnMount(false); // added in case /data is mounted as tmpfs for qcom hardware decrypt
 			Display_Name = "Data";
@@ -390,6 +392,11 @@
 			Display_Name = "Recovery";
 			Backup_Display_Name = Display_Name;
 			Can_Flash_Img = true;
+		} else if (Mount_Point == "/system_image") {
+			Display_Name = "System Image";
+			Backup_Display_Name = Display_Name;
+			Can_Flash_Img = false;
+			Can_Be_Backed_Up = true;
 		}
 	}
 
@@ -936,6 +943,7 @@
 
 bool TWPartition::Mount(bool Display_Error) {
 	int exfat_mounted = 0;
+	unsigned long flags = Mount_Flags;
 
 	if (Is_Mounted()) {
 		return true;
@@ -964,9 +972,15 @@
 #endif
 		}
 	}
+
+	if (Mount_Read_Only)
+		flags |= MS_RDONLY;
+
 	if (Fstab_File_System == "yaffs2") {
 		// mount an MTD partition as a YAFFS2 filesystem.
-		const unsigned long flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
+		flags = MS_NOATIME | MS_NODEV | MS_NODIRATIME;
+		if (Mount_Read_Only)
+			flags |= MS_RDONLY;
 		if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Fstab_File_System.c_str(), flags, NULL) < 0) {
 			if (mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), Fstab_File_System.c_str(), flags | MS_RDONLY, NULL) < 0) {
 				if (Display_Error)
@@ -1008,8 +1022,8 @@
 		mount_fs = "texfat";
 
 	if (!exfat_mounted &&
-		mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), Mount_Flags, Mount_Options.c_str()) != 0 &&
-		mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), Mount_Flags, NULL) != 0) {
+		mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), flags, Mount_Options.c_str()) != 0 &&
+		mount(Actual_Block_Device.c_str(), Mount_Point.c_str(), mount_fs.c_str(), flags, NULL) != 0) {
 #ifdef TW_NO_EXFAT_FUSE
 		if (Current_File_System == "exfat") {
 			LOGINFO("Mounting exfat failed, trying vfat...\n");
@@ -1018,7 +1032,7 @@
 					LOGERR("Unable to mount '%s'\n", Mount_Point.c_str());
 				else
 					LOGINFO("Unable to mount '%s'\n", Mount_Point.c_str());
-				LOGINFO("Actual block device: '%s', current file system: '%s', flags: 0x%8x, options: '%s'\n", Actual_Block_Device.c_str(), Current_File_System.c_str(), Mount_Flags, Mount_Options.c_str());
+				LOGINFO("Actual block device: '%s', current file system: '%s', flags: 0x%8x, options: '%s'\n", Actual_Block_Device.c_str(), Current_File_System.c_str(), flags, Mount_Options.c_str());
 				return false;
 			}
 		} else {
@@ -2138,3 +2152,37 @@
 	TWFunc::Exec_Cmd(Command);
 	return true;
 }
+
+void TWPartition::Change_Mount_Read_Only(bool new_value) {
+	Mount_Read_Only = new_value;
+}
+
+int TWPartition::Check_Lifetime_Writes() {
+	bool original_read_only = Mount_Read_Only;
+	int ret = 1;
+
+	Mount_Read_Only = true;
+	if (Mount(false)) {
+		Find_Actual_Block_Device();
+		string block = basename(Actual_Block_Device.c_str());
+		string file = "/sys/fs/" + Current_File_System + "/" + block + "/lifetime_write_kbytes";
+		string result;
+		if (TWFunc::Path_Exists(file)) {
+			if (TWFunc::read_file(file, result) != 0) {
+				LOGINFO("Check_Lifetime_Writes of '%s' failed to read_file\n", file.c_str());
+			} else {
+				LOGINFO("Check_Lifetime_Writes result: '%s'\n", result.c_str());
+				if (result == "0") {
+					ret = 0;
+				}
+			}
+		} else {
+			LOGINFO("Check_Lifetime_Writes file does not exist '%s'\n", file.c_str());
+		}
+		UnMount(true);
+	} else {
+		LOGINFO("Check_Lifetime_Writes failed to mount '%s'\n", Mount_Point.c_str());
+	}
+	Mount_Read_Only = original_read_only;
+	return ret;
+}