diff options
-rw-r--r-- | data.cpp | 2 | ||||
-rw-r--r-- | gui/action.cpp | 54 | ||||
-rw-r--r-- | gui/devices/1080x1920/res/ui.xml | 1 | ||||
-rw-r--r-- | gui/devices/320x320/res/ui.xml | 3 | ||||
-rw-r--r-- | gui/devices/480x800/res/ui.xml | 1 | ||||
-rw-r--r-- | gui/devices/landscape/res/landscape.xml | 98 | ||||
-rw-r--r-- | gui/devices/portrait/res/portrait.xml | 113 | ||||
-rw-r--r-- | gui/devices/watch/res/watch.xml | 111 | ||||
-rw-r--r-- | gui/objects.hpp | 2 | ||||
-rw-r--r-- | partition.cpp | 56 | ||||
-rw-r--r-- | partitionmanager.cpp | 6 | ||||
-rw-r--r-- | partitions.hpp | 3 | ||||
-rw-r--r-- | twrp.cpp | 16 |
13 files changed, 459 insertions, 7 deletions
@@ -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 342551247..7ecd0b46a 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 3135a03dc..a611d0582 100644 --- a/gui/devices/1080x1920/res/ui.xml +++ b/gui/devices/1080x1920/res/ui.xml @@ -86,6 +86,7 @@ <variable name="tz_selected_y" value="240" /> <variable name="tz_set_y" value="1500" /> <variable name="tz_current_y" value="1425" /> + <variable name="system_ro_y" value="1770" /> <variable name="col_progressbar_x" value="351" /> <variable name="row_progressbar_y" value="1650" /> <variable name="col1_medium_x" value="10" /> diff --git a/gui/devices/320x320/res/ui.xml b/gui/devices/320x320/res/ui.xml index 5495b7717..1dec40504 100644 --- a/gui/devices/320x320/res/ui.xml +++ b/gui/devices/320x320/res/ui.xml @@ -174,6 +174,7 @@ <variable name="row_offset_medium_y" value="206" /> <variable name="tz_set_y" value="271" /> <variable name="tz_current_y" value="249" /> + <variable name="system_ro_y" value="216" /> <variable name="button_fill_color" value="#303030" /> <variable name="button_fill_full_width" value="308" /> <variable name="button_fill_main_width" value="150" /> @@ -189,7 +190,7 @@ <variable name="backup_button_row1" value="214" /> <variable name="backup_button_row2" value="242" /> <variable name="mount_list_height" value="190" /> - <variable name="mount_storage_row" value="200" /> + <variable name="mount_storage_row" value="193" /> <variable name="storage_list_height" value="134" /> <variable name="wipe_list_height" value="216" /> <variable name="wipe_button_y" value="170" /> diff --git a/gui/devices/480x800/res/ui.xml b/gui/devices/480x800/res/ui.xml index 3c320a7eb..984454109 100644 --- a/gui/devices/480x800/res/ui.xml +++ b/gui/devices/480x800/res/ui.xml @@ -82,6 +82,7 @@ <variable name="tz_selected_y" value="110" /> <variable name="tz_set_y" value="580" /> <variable name="tz_current_y" value="730" /> + <variable name="system_ro_y" value="550" /> <variable name="col_progressbar_x" value="114" /> <variable name="row_progressbar_y" value="720" /> <variable name="col1_medium_x" value="10" /> diff --git a/gui/devices/landscape/res/landscape.xml b/gui/devices/landscape/res/landscape.xml index 25b9b17e7..12c66290b 100644 --- a/gui/devices/landscape/res/landscape.xml +++ b/gui/devices/landscape/res/landscape.xml @@ -989,6 +989,27 @@ </actions> </object> + <object type="button"> + <placement x="%col3_x%" y="%row10_text_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_false" /> + <action function="mountsystemtoggle"></action> + </object> + + <object type="button"> + <placement x="%col3_x%" y="%row10_text_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="!=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_true" /> + <actions> + <action function="set">tw_lifetime_writes=2</action> + <action function="page">system_readonly_check</action> + </actions> + </object> + <object type="action"> <touch key="home" /> <action function="page">main</action> @@ -1035,6 +1056,31 @@ <object type="template" name="footer" /> </page> + <page name="system_readonly_check"> + <object type="action"> + <action function="checkpartitionlifetimewrites">/system</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="1" /> + </conditions> + <action function="page">mount</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="0" /> + </conditions> + <actions> + <action function="set">tw_back=mount</action> + <action function="page">system_readonly</action> + </actions> + </object> + </page> + <page name="wipe"> <object type="template" name="header" /> @@ -3596,5 +3642,57 @@ </actions> </object> </page> + + <page name="system_readonly"> + <object type="template" name="header" /> + + <object type="text"> + <placement x="%center_x%" y="%row1_text_y%" placement="5" /> + <text>TWRP has detected an unmodified system partition.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row2_text_y%" placement="5" /> + <text>TWRP can leave your system partition unmodified to make it easier for you to take official updates.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row3_text_y%" placement="5" /> + <text>TWRP will be unable to prevent the stock ROM from replacing TWRP and will not offer to root your device.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row4_text_y%" placement="5" /> + <text>Installing zips or performing adb operations may still modify the system partition.</text> + </object> + + <object type="checkbox"> + <condition var1="tw_is_encrypted" var2="0" /> + <placement x="%col1_x%" y="%row5_text_y%" /> + <text>Never show this screen during boot again</text> + <data variable="tw_never_show_system_ro_page" /> + </object> + + <object type="button"> + <placement x="%col_center_x%" y="%row7_text_y%" /> + <text>Keep Read Only</text> + <actions> + <action function="set">tw_mount_system_ro=1</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + + <object type="slider"> + <text>Swipe to Allow Modifications</text> + <actions> + <action function="set">tw_mount_system_ro=0</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + + <object type="template" name="footer" /> + </page> </pages> </recovery> diff --git a/gui/devices/portrait/res/portrait.xml b/gui/devices/portrait/res/portrait.xml index bd235981d..997da9d23 100644 --- a/gui/devices/portrait/res/portrait.xml +++ b/gui/devices/portrait/res/portrait.xml @@ -2105,6 +2105,27 @@ <action function="page">decrypt</action> </object> + <object type="button"> + <placement x="%col1_x%" y="%system_ro_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_false" /> + <action function="mountsystemtoggle"></action> + </object> + + <object type="button"> + <placement x="%col1_x%" y="%system_ro_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="!=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_true" /> + <actions> + <action function="set">tw_lifetime_writes=2</action> + <action function="page">system_readonly_check</action> + </actions> + </object> + <object type="action"> <touch key="home" /> <action function="page">main</action> @@ -2161,6 +2182,31 @@ </object> </page> + <page name="system_readonly_check"> + <object type="action"> + <action function="checkpartitionlifetimewrites">/system</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="1" /> + </conditions> + <action function="page">mount</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="0" /> + </conditions> + <actions> + <action function="set">tw_back=mount</action> + <action function="page">system_readonly</action> + </actions> + </object> + </page> + <page name="reboot"> <object type="template" name="header" /> @@ -3607,5 +3653,72 @@ </actions> </object> </page> + + <page name="system_readonly"> + <object type="template" name="header" /> + + <object type="text"> + <placement x="%center_x%" y="%row1_header_y%" placement="5" /> + <text>TWRP has detected an unmodified system partition.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row2_text_y%" placement="5" /> + <text>TWRP can leave your system partition unmodified</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row3_text_y%" placement="5" /> + <text>to make it easier for you to take official updates.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row4_text_y%" placement="5" /> + <text>TWRP will be unable to prevent the stock ROM from</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row5_text_y%" placement="5" /> + <text>replacing TWRP and will not offer to root your device.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row6_text_y%" placement="5" /> + <text>Installing zips or performing adb operations may still</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row7_text_y%" placement="5" /> + <text>modify the system partition.</text> + </object> + + <object type="checkbox"> + <condition var1="tw_is_encrypted" var2="0" /> + <placement x="%col1_x%" y="%row8_text_y%" /> + <text>Never show this screen during boot again</text> + <data variable="tw_never_show_system_ro_page" /> + </object> + + <object type="button"> + <placement x="%col_center_x%" y="%row10_text_y%" /> + <text>Keep Read Only</text> + <actions> + <action function="set">tw_mount_system_ro=1</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + + <object type="slider"> + <text>Swipe to Allow Modifications</text> + <actions> + <action function="set">tw_mount_system_ro=0</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + + <object type="template" name="footer" /> + </page> </pages> </recovery> diff --git a/gui/devices/watch/res/watch.xml b/gui/devices/watch/res/watch.xml index 872c47b6b..f0f383dcb 100644 --- a/gui/devices/watch/res/watch.xml +++ b/gui/devices/watch/res/watch.xml @@ -2113,6 +2113,27 @@ <action function="page">decrypt</action> </object> + <object type="button"> + <placement x="%col1_x%" y="%system_ro_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_false" /> + <action function="mountsystemtoggle"></action> + </object> + + <object type="button"> + <placement x="%col1_x%" y="%system_ro_y%" /> + <font resource="font" color="%text_color%" /> + <condition var1="tw_mount_system_ro" op="!=" var2="0" /> + <text>Only mount system read-only</text> + <image resource="checkbox_true" /> + <actions> + <action function="set">tw_lifetime_writes=2</action> + <action function="page">system_readonly_check</action> + </actions> + </object> + <object type="action"> <touch key="home" /> <action function="page">main</action> @@ -2168,6 +2189,31 @@ </object> </page> + <page name="system_readonly_check"> + <object type="action"> + <action function="checkpartitionlifetimewrites">/system</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="1" /> + </conditions> + <action function="page">mount</action> + </object> + + <object type="action"> + <conditions> + <condition var1="tw_operation_state" var2="1" /> + <condition var1="tw_lifetime_writes" var2="0" /> + </conditions> + <actions> + <action function="set">tw_back=mount</action> + <action function="page">system_readonly</action> + </actions> + </object> + </page> + <page name="reboot"> <object type="template" name="header" /> @@ -3596,5 +3642,70 @@ </actions> </object> </page> + + <page name="system_readonly"> + <object type="template" name="header" /> + + <object type="text"> + <placement x="%center_x%" y="%row1_header_y%" placement="5" /> + <text>TWRP has detected an unmodified system partition.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row1_text_y%" placement="5" /> + <text>TWRP can leave your system partition unmodified</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row2_text_y%" placement="5" /> + <text>to make it easier for you to take official updates.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row3_text_y%" placement="5" /> + <text>TWRP will be unable to prevent the stock ROM from</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row4_text_y%" placement="5" /> + <text>replacing TWRP and will not offer to root your device.</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row5_text_y%" placement="5" /> + <text>Installing zips or performing adb operations may still</text> + </object> + + <object type="text"> + <placement x="%center_x%" y="%row6_text_y%" placement="5" /> + <text>modify the system partition.</text> + </object> + + <object type="checkbox"> + <condition var1="tw_is_encrypted" var2="0" /> + <placement x="%col1_x%" y="%row7_text_y%" /> + <text>Never show this screen during boot again</text> + <data variable="tw_never_show_system_ro_page" /> + </object> + + <object type="button"> + <placement x="%col_center_x%" y="%row9_text_y%" /> + <text>Keep Read Only</text> + <actions> + <action function="set">tw_mount_system_ro=1</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + + <object type="slider"> + <text>Swipe to Allow Modifications</text> + <actions> + <action function="set">tw_mount_system_ro=0</action> + <action function="set">tw_page_done=1</action> + <action function="page">%tw_back%</action> + </actions> + </object> + </page> </pages> </recovery> diff --git a/gui/objects.hpp b/gui/objects.hpp index e70053e3b..ee0f08b8f 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 248ee9bc2..2f9f41a69 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 ffc17c3a4..055f73697 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<TWPartition*>::iterator subpart; diff --git a/partitions.hpp b/partitions.hpp index f74fac9a1..1489a8ec2 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; @@ -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); |