From a449a6f504ca0cd6f900327af4f91b016a352cd0 Mon Sep 17 00:00:00 2001 From: Dees_Troy Date: Sun, 7 Apr 2013 17:50:11 -0500 Subject: Fix handling of AOSP recovery commands --- bootloader.cpp | 72 +++++++++ bootloader.h | 2 + twrp.cpp | 493 +++++++++++++++++++++++++++++---------------------------- 3 files changed, 326 insertions(+), 241 deletions(-) diff --git a/bootloader.cpp b/bootloader.cpp index 6b42b947a..ff0dc6826 100644 --- a/bootloader.cpp +++ b/bootloader.cpp @@ -265,3 +265,75 @@ int set_bootloader_message_block_name(const struct bootloader_message *in, } return 0; } + +static const char *COMMAND_FILE = "/cache/recovery/command"; +static const int MAX_ARG_LENGTH = 4096; +static const int MAX_ARGS = 100; + +// command line args come from, in decreasing precedence: +// - the actual command line +// - the bootloader control block (one per line, after "recovery") +// - the contents of COMMAND_FILE (one per line) +void +get_args(int *argc, char ***argv) { + struct bootloader_message boot; + memset(&boot, 0, sizeof(boot)); + get_bootloader_message(&boot); // this may fail, leaving a zeroed structure + + if (boot.command[0] != 0 && boot.command[0] != 255) { + LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command); + } + + if (boot.status[0] != 0 && boot.status[0] != 255) { + LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status); + } + + // --- if arguments weren't supplied, look in the bootloader control block + if (*argc <= 1) { + boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination + const char *arg = strtok(boot.recovery, "\n"); + if (arg != NULL && !strcmp(arg, "recovery")) { + *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); + (*argv)[0] = strdup(arg); + for (*argc = 1; *argc < MAX_ARGS; ++*argc) { + if ((arg = strtok(NULL, "\n")) == NULL) break; + (*argv)[*argc] = strdup(arg); + } + LOGI("Got arguments from boot message\n"); + } else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) { + LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery); + } + } + + // --- if that doesn't work, try the command file + if (*argc <= 1) { + FILE *fp = fopen(COMMAND_FILE, "r"); + if (fp != NULL) { + char *argv0 = (*argv)[0]; + *argv = (char **) malloc(sizeof(char *) * MAX_ARGS); + (*argv)[0] = argv0; // use the same program name + + char buf[MAX_ARG_LENGTH]; + for (*argc = 1; *argc < MAX_ARGS; ++*argc) { + if (!fgets(buf, sizeof(buf), fp)) break; + (*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline. + } + + fflush(fp); + if (ferror(fp)) LOGE("Error in %s\n(%s)\n", COMMAND_FILE, strerror(errno)); + fclose(fp); + LOGI("Got arguments from %s\n", COMMAND_FILE); + } + } + + // --> write the arguments we have back into the bootloader control block + // always boot into recovery after this (until finish_recovery() is called) + strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); + strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery)); + int i; + for (i = 1; i < *argc; ++i) { + strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery)); + strlcat(boot.recovery, "\n", sizeof(boot.recovery)); + } + set_bootloader_message(&boot); +} diff --git a/bootloader.h b/bootloader.h index 38bb19e9b..ead1d0b52 100644 --- a/bootloader.h +++ b/bootloader.h @@ -54,6 +54,8 @@ int set_bootloader_message(const struct bootloader_message *in); int set_bootloader_message_mtd_name(const struct bootloader_message *in, const char* mtd_name); int set_bootloader_message_block_name(const struct bootloader_message *in, const char* block_name); +void get_args(int *argc, char ***argv); + #ifdef __cplusplus } #endif diff --git a/twrp.cpp b/twrp.cpp index 9825ebf52..bc3ce7b6d 100644 --- a/twrp.cpp +++ b/twrp.cpp @@ -1,241 +1,252 @@ -/* - Copyright 2013 bigbiff/Dees_Troy TeamWin - This file is part of TWRP/TeamWin Recovery Project. - - TWRP is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - TWRP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with TWRP. If not, see . -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "cutils/properties.h" -extern "C" { -#include "minadbd/adb.h" -} - -#ifdef ANDROID_RB_RESTART -#include "cutils/android_reboot.h" -#else -#include -#endif - -extern "C" { -#include "gui/gui.h" -} -#include "twcommon.h" -#include "twrp-functions.hpp" -#include "data.hpp" -#include "partitions.hpp" -#include "openrecoveryscript.hpp" -#include "variables.h" - -TWPartitionManager PartitionManager; -int Log_Offset; - -static void Print_Prop(const char *key, const char *name, void *cookie) { - printf("%s=%s\n", key, name); -} - -int main(int argc, char **argv) { - // Recovery needs to install world-readable files, so clear umask - // set by init - umask(0); - - Log_Offset = 0; - - // Set up temporary log file (/tmp/recovery.log) - freopen(TMP_LOG_FILE, "a", stdout); - setbuf(stdout, NULL); - freopen(TMP_LOG_FILE, "a", stderr); - setbuf(stderr, NULL); - - // Handle ADB sideload - if (argc == 3 && strcmp(argv[1], "--adbd") == 0) { - adb_main(argv[2]); - return 0; - } - - time_t StartupTime = time(NULL); - printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&StartupTime)); - - // Load default values to set DataManager constants and handle ifdefs - DataManager::SetDefaultValues(); - printf("Starting the UI..."); - gui_init(); - printf("=> Linking mtab\n"); - symlink("/proc/mounts", "/etc/mtab"); - printf("=> Processing recovery.fstab\n"); - if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) { - LOGERR("Failing out of recovery due to problem with recovery.fstab.\n"); - return -1; - } - PartitionManager.Output_Partition_Logging(); - // Load up all the resources - gui_loadResources(); - - PartitionManager.Mount_By_Path("/cache", true); - - string Zip_File, Reboot_Value; - bool Cache_Wipe = false, Factory_Reset = false, Perform_Backup = false; - - int index, index2; - char* ptr; - printf("Startup Commands: "); - for (index = 1; index < argc; index++) { - printf(" '%s'", argv[index]); - if (*argv[index] == 'u') { - ptr = argv[index]; - index2 = 0; - while (*ptr != '=' && *ptr != '\n') - ptr++; - if (*ptr) { - Zip_File = ptr; - } else - LOGERR("argument error specifying zip file\n"); - } else if (*argv[index] == 'c') { - Cache_Wipe = true; - } else if (*argv[index] == 'w') { - Factory_Reset = true; - } else if (*argv[index] == 'n') { - Perform_Backup = true; - } else if (*argv[index] == 's') { - ptr = argv[index]; - index2 = 0; - while (*ptr != '=' && *ptr != '\n') - ptr++; - if (*ptr) { - Reboot_Value = *ptr; - } - } - } - - char twrp_booted[PROPERTY_VALUE_MAX]; - property_get("ro.twrp.boot", twrp_booted, "0"); - if (strcmp(twrp_booted, "0") == 0) { - property_list(Print_Prop, NULL); - printf("\n"); - property_set("ro.twrp.boot", "1"); - } - - // Check for and run startup script if script exists - TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot"); - TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot"); - -#ifdef TW_INCLUDE_INJECTTWRP - // Back up TWRP Ramdisk if needed: - TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); - string result; - LOGINFO("Backing up TWRP ramdisk...\n"); - if (Boot == NULL || Boot->Current_File_System != "emmc") - TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img", result); - else { - string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device; - TWFunc::Exec_Cmd(injectcmd, result); - } - LOGINFO("Backup of TWRP ramdisk done.\n"); -#endif - - bool Keep_Going = true; - if (Perform_Backup) { - DataManager::SetValue(TW_BACKUP_NAME, "(Current Date)"); - if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n")) - Keep_Going = false; - } - if (Keep_Going && !Zip_File.empty()) { - string ORSCommand = "install " + Zip_File; - - if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand)) - Keep_Going = false; - } - if (Keep_Going) { - if (Factory_Reset) { - if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n")) - Keep_Going = false; - } else if (Cache_Wipe) { - if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n")) - Keep_Going = false; - } - } - - TWFunc::Update_Log_File(); - // Offer to decrypt if the device is encrypted - if (DataManager::GetIntValue(TW_IS_ENCRYPTED) != 0) { - LOGINFO("Is encrypted, do decrypt page first\n"); - if (gui_startPage("decrypt") != 0) { - LOGERR("Failed to start decrypt GUI page.\n"); - } - } - - // Read the settings file - DataManager::ReadSettingsFile(); - // Run any outstanding OpenRecoveryScript - if (DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) { - OpenRecoveryScript::Run_OpenRecoveryScript(); - } - // Launch the main GUI - gui_start(); - - // Check for su to see if the device is rooted or not - if (PartitionManager.Mount_By_Path("/system", false)) { - // Disable flashing of stock recovery - if (TWFunc::Path_Exists("/system/recovery-from-boot.p")) { - rename("/system/recovery-from-boot.p", "/system/recovery-from-boot.bak"); - gui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n"); - } - 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); - if (gui_startPage("installsu") != 0) { - LOGERR("Failed to start decrypt GUI page.\n"); - } - } else if (TWFunc::Check_su_Perms() > 0) { - // su perms are set incorrectly - DataManager::SetValue("tw_busy", 1); - if (gui_startPage("fixsu") != 0) { - LOGERR("Failed to start decrypt GUI page.\n"); - } - } - sync(); - PartitionManager.UnMount_By_Path("/system", false); - } - - // Reboot - TWFunc::Update_Intent_File(Reboot_Value); - TWFunc::Update_Log_File(); - gui_print("Rebooting...\n"); - string Reboot_Arg; - DataManager::GetValue("tw_reboot_arg", Reboot_Arg); - if (Reboot_Arg == "recovery") - TWFunc::tw_reboot(rb_recovery); - else if (Reboot_Arg == "poweroff") - TWFunc::tw_reboot(rb_poweroff); - else if (Reboot_Arg == "bootloader") - TWFunc::tw_reboot(rb_bootloader); - else if (Reboot_Arg == "download") - TWFunc::tw_reboot(rb_download); - else - TWFunc::tw_reboot(rb_system); - -#ifdef ANDROID_RB_RESTART - android_reboot(ANDROID_RB_RESTART, 0, 0); -#else - reboot(RB_AUTOBOOT); -#endif - return 0; -} +/* + Copyright 2013 bigbiff/Dees_Troy TeamWin + This file is part of TWRP/TeamWin Recovery Project. + + TWRP is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + TWRP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with TWRP. If not, see . +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "cutils/properties.h" +extern "C" { +#include "minadbd/adb.h" +#include "bootloader.h" +} + +#ifdef ANDROID_RB_RESTART +#include "cutils/android_reboot.h" +#else +#include +#endif + +extern "C" { +#include "gui/gui.h" +} +#include "twcommon.h" +#include "twrp-functions.hpp" +#include "data.hpp" +#include "partitions.hpp" +#include "openrecoveryscript.hpp" +#include "variables.h" + +TWPartitionManager PartitionManager; +int Log_Offset; + +static void Print_Prop(const char *key, const char *name, void *cookie) { + printf("%s=%s\n", key, name); +} + +int main(int argc, char **argv) { + // Recovery needs to install world-readable files, so clear umask + // set by init + umask(0); + + Log_Offset = 0; + + // Set up temporary log file (/tmp/recovery.log) + freopen(TMP_LOG_FILE, "a", stdout); + setbuf(stdout, NULL); + freopen(TMP_LOG_FILE, "a", stderr); + setbuf(stderr, NULL); + + // Handle ADB sideload + if (argc == 3 && strcmp(argv[1], "--adbd") == 0) { + adb_main(argv[2]); + return 0; + } + + time_t StartupTime = time(NULL); + printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&StartupTime)); + + // Load default values to set DataManager constants and handle ifdefs + DataManager::SetDefaultValues(); + printf("Starting the UI..."); + gui_init(); + printf("=> Linking mtab\n"); + symlink("/proc/mounts", "/etc/mtab"); + printf("=> Processing recovery.fstab\n"); + if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) { + LOGERR("Failing out of recovery due to problem with recovery.fstab.\n"); + return -1; + } + PartitionManager.Output_Partition_Logging(); + // Load up all the resources + gui_loadResources(); + + PartitionManager.Mount_By_Path("/cache", true); + + string Zip_File, Reboot_Value; + bool Cache_Wipe = false, Factory_Reset = false, Perform_Backup = false; + + { + get_args(&argc, &argv); + + int index, index2, len; + char* argptr; + char* ptr; + printf("Startup Commands: "); + for (index = 1; index < argc; index++) { + argptr = argv[index]; + printf(" '%s'", argv[index]); + len = strlen(argv[index]); + if (*argptr == '-') {argptr++; len--;} + if (*argptr == '-') {argptr++; len--;} + if (*argptr == 'u') { + ptr = argptr; + index2 = 0; + while (*ptr != '=' && *ptr != '\n') + ptr++; + if (*ptr) { + Zip_File = ptr; + } else + LOGERR("argument error specifying zip file\n"); + } else if (*argptr == 'w') { + if (len == 9) + Factory_Reset = true; + else if (len == 10) + Cache_Wipe = true; + } else if (*argptr == 'n') { + Perform_Backup = true; + } else if (*argptr == 's') { + ptr = argptr; + index2 = 0; + while (*ptr != '=' && *ptr != '\n') + ptr++; + if (*ptr) { + Reboot_Value = *ptr; + } + } + } + } + + char twrp_booted[PROPERTY_VALUE_MAX]; + property_get("ro.twrp.boot", twrp_booted, "0"); + if (strcmp(twrp_booted, "0") == 0) { + property_list(Print_Prop, NULL); + printf("\n"); + property_set("ro.twrp.boot", "1"); + } + + // Check for and run startup script if script exists + TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot"); + TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot"); + +#ifdef TW_INCLUDE_INJECTTWRP + // Back up TWRP Ramdisk if needed: + TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot"); + string result; + LOGINFO("Backing up TWRP ramdisk...\n"); + if (Boot == NULL || Boot->Current_File_System != "emmc") + TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img", result); + else { + string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device; + TWFunc::Exec_Cmd(injectcmd, result); + } + LOGINFO("Backup of TWRP ramdisk done.\n"); +#endif + + bool Keep_Going = true; + if (Perform_Backup) { + DataManager::SetValue(TW_BACKUP_NAME, "(Current Date)"); + if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n")) + Keep_Going = false; + } + if (Keep_Going && !Zip_File.empty()) { + string ORSCommand = "install " + Zip_File; + + if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand)) + Keep_Going = false; + } + if (Keep_Going) { + if (Factory_Reset) { + if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n")) + Keep_Going = false; + } else if (Cache_Wipe) { + if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n")) + Keep_Going = false; + } + } + + TWFunc::Update_Log_File(); + // Offer to decrypt if the device is encrypted + if (DataManager::GetIntValue(TW_IS_ENCRYPTED) != 0) { + LOGINFO("Is encrypted, do decrypt page first\n"); + if (gui_startPage("decrypt") != 0) { + LOGERR("Failed to start decrypt GUI page.\n"); + } + } + + // Read the settings file + DataManager::ReadSettingsFile(); + // Run any outstanding OpenRecoveryScript + if (DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) { + OpenRecoveryScript::Run_OpenRecoveryScript(); + } + // Launch the main GUI + gui_start(); + + // Check for su to see if the device is rooted or not + if (PartitionManager.Mount_By_Path("/system", false)) { + // Disable flashing of stock recovery + if (TWFunc::Path_Exists("/system/recovery-from-boot.p")) { + rename("/system/recovery-from-boot.p", "/system/recovery-from-boot.bak"); + gui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n"); + } + 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); + if (gui_startPage("installsu") != 0) { + LOGERR("Failed to start decrypt GUI page.\n"); + } + } else if (TWFunc::Check_su_Perms() > 0) { + // su perms are set incorrectly + DataManager::SetValue("tw_busy", 1); + if (gui_startPage("fixsu") != 0) { + LOGERR("Failed to start decrypt GUI page.\n"); + } + } + sync(); + PartitionManager.UnMount_By_Path("/system", false); + } + + // Reboot + TWFunc::Update_Intent_File(Reboot_Value); + TWFunc::Update_Log_File(); + gui_print("Rebooting...\n"); + string Reboot_Arg; + DataManager::GetValue("tw_reboot_arg", Reboot_Arg); + if (Reboot_Arg == "recovery") + TWFunc::tw_reboot(rb_recovery); + else if (Reboot_Arg == "poweroff") + TWFunc::tw_reboot(rb_poweroff); + else if (Reboot_Arg == "bootloader") + TWFunc::tw_reboot(rb_bootloader); + else if (Reboot_Arg == "download") + TWFunc::tw_reboot(rb_download); + else + TWFunc::tw_reboot(rb_system); + +#ifdef ANDROID_RB_RESTART + android_reboot(ANDROID_RB_RESTART, 0, 0); +#else + reboot(RB_AUTOBOOT); +#endif + return 0; +} -- cgit v1.2.3