diff --git a/data.cpp b/data.cpp index 0ce4ddc3..eb8b5534 100644 --- a/data.cpp +++ b/data.cpp @@ -852,6 +852,8 @@ void DataManager::SetDefaultValues() mConstValues.insert(make_pair("tw_has_mtp", "0")); mConstValues.insert(make_pair("tw_mtp_enabled", "0")); #endif + mValues.insert(make_pair("tw_mount_system_ro", make_pair("1", 1))); + mValues.insert(make_pair("tw_never_show_system_ro_page", make_pair("0", 1))); pthread_mutex_unlock(&m_valuesLock); } diff --git a/gui/action.cpp b/gui/action.cpp index 34255124..7ecd0b46 100644 --- a/gui/action.cpp +++ b/gui/action.cpp @@ -196,6 +196,8 @@ GUIAction::GUIAction(xml_node<>* node) ADD_ACTION(startmtp); ADD_ACTION(stopmtp); ADD_ACTION(cancelbackup); + ADD_ACTION(checkpartitionlifetimewrites); + ADD_ACTION(mountsystemtoggle); // remember actions that run in the caller thread for (mapFunc::const_iterator it = mf.begin(); it != mf.end(); ++it) @@ -1737,3 +1739,55 @@ int GUIAction::getKeyByName(std::string key) return atol(key.c_str()); } + +int GUIAction::checkpartitionlifetimewrites(std::string arg) +{ + int op_status = 0; + TWPartition* sys = PartitionManager.Find_Partition_By_Path(arg); + + operation_start("Check Partition Lifetime Writes"); + if (sys) { + if (sys->Check_Lifetime_Writes() != 0) + DataManager::SetValue("tw_lifetime_writes", 1); + else + DataManager::SetValue("tw_lifetime_writes", 0); + op_status = 0; // success + } else { + DataManager::SetValue("tw_lifetime_writes", 1); + op_status = 1; // fail + } + + operation_end(op_status); + return 0; +} + +int GUIAction::mountsystemtoggle(std::string arg) +{ + int op_status = 0; + bool remount_system = PartitionManager.Is_Mounted_By_Path("/system"); + + operation_start("Toggle System Mount"); + if (!PartitionManager.UnMount_By_Path("/system", true)) { + op_status = 1; // fail + } else { + TWPartition* Part = PartitionManager.Find_Partition_By_Path("/system"); + if (Part) { + if (DataManager::GetIntValue("tw_mount_system_ro")) { + DataManager::SetValue("tw_mount_system_ro", 0); + Part->Change_Mount_Read_Only(false); + } else { + DataManager::SetValue("tw_mount_system_ro", 1); + Part->Change_Mount_Read_Only(true); + } + if (remount_system) { + Part->Mount(true); + } + op_status = 0; // success + } else { + op_status = 1; // fail + } + } + + operation_end(op_status); + return 0; +} diff --git a/gui/devices/1080x1920/res/ui.xml b/gui/devices/1080x1920/res/ui.xml index 3135a03d..a611d058 100644 --- a/gui/devices/1080x1920/res/ui.xml +++ b/gui/devices/1080x1920/res/ui.xml @@ -86,6 +86,7 @@ + diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml index 5495b771..1dec4050 100644 --- a/gui/devices/320x320/res/ui.xml +++ b/gui/devices/320x320/res/ui.xml @@ -174,6 +174,7 @@ + @@ -189,7 +190,7 @@ - + diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml index 3c320a7e..98445410 100644 --- a/gui/devices/480x800/res/ui.xml +++ b/gui/devices/480x800/res/ui.xml @@ -82,6 +82,7 @@ + diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml index 25b9b17e..12c66290 100644 --- a/gui/devices/landscape/res/landscape.xml +++ b/gui/devices/landscape/res/landscape.xml @@ -989,6 +989,27 @@ + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -1035,6 +1056,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3596,5 +3642,57 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + + + diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml index bd235981..997da9d2 100644 --- a/gui/devices/portrait/res/portrait.xml +++ b/gui/devices/portrait/res/portrait.xml @@ -2105,6 +2105,27 @@ decrypt + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -2161,6 +2182,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3607,5 +3653,72 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified + + + + + to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from + + + + + replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still + + + + + modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + + + diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml index 872c47b6..f0f383dc 100644 --- a/gui/devices/watch/res/watch.xml +++ b/gui/devices/watch/res/watch.xml @@ -2113,6 +2113,27 @@ decrypt + + + + + Only mount system read-only + + + + + + + + + Only mount system read-only + + + tw_lifetime_writes=2 + system_readonly_check + + + main @@ -2168,6 +2189,31 @@ + + + /system + + + + + + + + mount + + + + + + + + + tw_back=mount + system_readonly + + + + @@ -3596,5 +3642,70 @@ + + + + + + + TWRP has detected an unmodified system partition. + + + + + TWRP can leave your system partition unmodified + + + + + to make it easier for you to take official updates. + + + + + TWRP will be unable to prevent the stock ROM from + + + + + replacing TWRP and will not offer to root your device. + + + + + Installing zips or performing adb operations may still + + + + + modify the system partition. + + + + + + Never show this screen during boot again + + + + + + Keep Read Only + + tw_mount_system_ro=1 + tw_page_done=1 + %tw_back% + + + + + Swipe to Allow Modifications + + tw_mount_system_ro=0 + tw_page_done=1 + %tw_back% + + + diff --git a/gui/objects.hpp b/gui/objects.hpp index e70053e3..ee0f08b8 100644 --- a/gui/objects.hpp +++ b/gui/objects.hpp @@ -359,6 +359,8 @@ protected: int stopmtp(std::string arg); int flashimage(std::string arg); int cancelbackup(std::string arg); + int checkpartitionlifetimewrites(std::string arg); + int mountsystemtoggle(std::string arg); int simulate; }; diff --git a/partition.cpp b/partition.cpp index 248ee9bc..2f9f41a6 100644 --- a/partition.cpp +++ b/partition.cpp @@ -155,6 +155,7 @@ TWPartition::TWPartition() { Crypto_Key_Location = "footer"; MTP_Storage_ID = 0; Can_Flash_Img = false; + Mount_Read_Only = false; } TWPartition::~TWPartition(void) { @@ -258,6 +259,7 @@ bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) { 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 @@ bool TWPartition::Process_Fstab_Line(string Line, bool Display_Error) { 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::Is_Mounted(void) { bool TWPartition::Mount(bool Display_Error) { int exfat_mounted = 0; + unsigned long flags = Mount_Flags; if (Is_Mounted()) { return true; @@ -964,9 +972,15 @@ bool TWPartition::Mount(bool Display_Error) { #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 @@ bool TWPartition::Mount(bool Display_Error) { 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 @@ bool TWPartition::Mount(bool Display_Error) { 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 @@ bool TWPartition::Flash_Image_FI(string Filename) { 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; +} diff --git a/partitionmanager.cpp b/partitionmanager.cpp index ffc17c3a..055f7369 100644 --- a/partitionmanager.cpp +++ b/partitionmanager.cpp @@ -880,9 +880,13 @@ int TWPartitionManager::Run_Restore(string Restore_Name) { restore_path = Restore_List.substr(start_pos, end_pos - start_pos); restore_part = Find_Partition_By_Path(restore_path); if (restore_part != NULL) { - partition_count++; + if (restore_part->Mount_Read_Only) { + LOGERR("Cannot restore %s -- mounted read only.\n", restore_part->Backup_Display_Name.c_str()); + return false; + } if (check_md5 > 0 && !restore_part->Check_MD5(Restore_Name)) return false; + partition_count++; total_restore_size += restore_part->Get_Restore_Size(Restore_Name); if (restore_part->Has_SubPartition) { std::vector::iterator subpart; diff --git a/partitions.hpp b/partitions.hpp index f74fac9a..1489a8ec 100644 --- a/partitions.hpp +++ b/partitions.hpp @@ -70,6 +70,8 @@ public: bool Update_Size(bool Display_Error); // Updates size information void Recreate_Media_Folder(); // Recreates the /data/media folder bool Flash_Image(string Filename); // Flashes an image to the partition + void Change_Mount_Read_Only(bool new_value); // Changes Mount_Read_Only to new_value + int Check_Lifetime_Writes(); public: string Current_File_System; // Current file system @@ -167,6 +169,7 @@ private: bool Ignore_Blkid; // Ignore blkid results due to superblocks lying to us on certain devices / partitions bool Retain_Layout_Version; // Retains the .layout_version file during a wipe (needed on devices like Sony Xperia T where /data and /data/media are separate partitions) bool Can_Flash_Img; // Indicates if this partition can have images flashed to it via the GUI + bool Mount_Read_Only; // Only mount this partition as read-only friend class TWPartitionManager; friend class DataManager; diff --git a/twrp.cpp b/twrp.cpp index 0c012d7e..b7fc9815 100644 --- a/twrp.cpp +++ b/twrp.cpp @@ -332,13 +332,27 @@ int main(int argc, char **argv) { PartitionManager.Disable_MTP(); #endif + // Check if system has never been changed + if (DataManager::GetIntValue("tw_mount_system_ro") != 0 && DataManager::GetIntValue("tw_never_show_system_ro_page") == 0) { + TWPartition* sys = PartitionManager.Find_Partition_By_Path("/system"); + if (sys && sys->Check_Lifetime_Writes() == 0) { + LOGINFO("System writes is 0, show system_readonly page\n"); + DataManager::SetValue("tw_back", "main"); + if (gui_startPage("system_readonly", 1, 1) != 0) { + LOGERR("Failed to start system_readonly GUI page.\n"); + } + } else { + DataManager::SetValue("tw_mount_system_ro", 0); + } + } + // Launch the main GUI gui_start(); // Disable flashing of stock recovery TWFunc::Disable_Stock_Recovery_Replace(); // Check for su to see if the device is rooted or not - if (PartitionManager.Mount_By_Path("/system", false)) { + if (PartitionManager.Mount_By_Path("/system", false) && DataManager::GetIntValue("tw_mount_system_ro") == 0) { if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) { // Device doesn't have su installed DataManager::SetValue("tw_busy", 1);