fastboot: implement fastbootd in twrp

fastbootd is a userspace daemon that runs in the recovery
ramdisk. It allows writing single partitions to the super
partition via fastboot CLI. When TWRP sees the fastboot option
in the misc partition during startup, it will start with
the fastbootd page and fastbootd running. Otherwise it will
run recovery normally.

Change-Id: Id7b12d29ef21dbd5950dc884dd1cd788f25357f0
diff --git a/twrp.cpp b/twrp.cpp
index 584245b..7ec428c 100755
--- a/twrp.cpp
+++ b/twrp.cpp
@@ -1,16 +1,19 @@
 /*
-		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.
+	Copyright 2012-2020 TeamWin
+	This file is part of TWRP/TeamWin Recovery Project.
 
-		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.
+	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.
 
-		You should have received a copy of the GNU General Public License
-		along with TWRP.  If not, see <http://www.gnu.org/licenses/>.
+	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 <http://www.gnu.org/licenses/>.
 */
 
 #include <stdio.h>
@@ -24,7 +27,6 @@
 #include "gui/twmsg.h"
 
 #include "cutils/properties.h"
-#include "bootloader_message_twrp/include/bootloader_message_twrp/bootloader_message.h"
 
 #ifdef ANDROID_RB_RESTART
 #include "cutils/android_reboot.h"
@@ -50,6 +52,7 @@
 #endif
 #include "openrecoveryscript.hpp"
 #include "variables.h"
+#include "startupArgs.hpp"
 #include "twrpAdbBuFifo.hpp"
 #ifdef TW_USE_NEW_MINADBD
 // #include "minadbd/minadbd.h"
@@ -96,53 +99,21 @@
 	}
 }
 
-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);
-
-	signal(SIGPIPE, SIG_IGN);
-
-	// Handle ADB sideload
-	if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
-		property_set("ctl.stop", "adbd");
-#ifdef TW_USE_NEW_MINADBD
-		//adb_server_main(0, DEFAULT_ADB_PORT, -1); TODO fix this for android8
-		// minadbd_main();
-#else
-		adb_main(argv[2]);
-#endif
-		return 0;
-	}
-
-#ifdef RECOVERY_SDCARD_ON_DATA
-	datamedia = true;
-#endif
-
+static void process_recovery_mode(twrpAdbBuFifo* adb_bu_fifo, bool skip_decryption) {
 	char crash_prop_val[PROPERTY_VALUE_MAX];
 	int crash_counter;
 	property_get("twrp.crash_counter", crash_prop_val, "-1");
 	crash_counter = atoi(crash_prop_val) + 1;
 	snprintf(crash_prop_val, sizeof(crash_prop_val), "%d", crash_counter);
 	property_set("twrp.crash_counter", crash_prop_val);
-	property_set("ro.twrp.boot", "1");
-	property_set("ro.twrp.version", TW_VERSION_STR);
 
-	time_t StartupTime = time(NULL);
-	printf("Starting TWRP %s-%s on %s (pid %d)\n", TW_VERSION_STR, TW_GIT_REVISION, ctime(&StartupTime), getpid());
+	if (crash_counter == 0) {
+		property_list(Print_Prop, NULL);
+		printf("\n");
+	} else {
+		printf("twrp.crash_counter=%d\n", crash_counter);
+	}
 
-	// Load default values to set DataManager constants and handle ifdefs
-	DataManager::SetDefaultValues();
-	printf("Starting the UI...\n");
-	gui_init();
 	printf("=> Linking mtab\n");
 	symlink("/proc/mounts", "/etc/mtab");
 	std::string fstab_filename = "/etc/twrp.fstab";
@@ -152,7 +123,7 @@
 	printf("=> Processing %s\n", fstab_filename.c_str());
 	if (!PartitionManager.Process_Fstab(fstab_filename, 1)) {
 		LOGERR("Failing out of recovery due to problem with fstab.\n");
-		return -1;
+		return;
 	}
 	PartitionManager.Output_Partition_Logging();
 
@@ -188,96 +159,6 @@
 	}
 #endif
 
-	// Load up all the resources
-	gui_loadResources();
-
-	bool Shutdown = false;
-	bool SkipDecryption = false;
-	string Send_Intent = "";
-	{
-		TWPartition* misc = PartitionManager.Find_Partition_By_Path("/misc");
-		if (misc != NULL) {
-			if (misc->Current_File_System == "emmc") {
-				set_misc_device(misc->Actual_Block_Device.c_str());
-			} else {
-				LOGERR("Only emmc /misc is supported\n");
-			}
-		}
-		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++;
-				// skip the = before grabbing Zip_File
-				while (*ptr == '=')
-					ptr++;
-				if (*ptr) {
-					string ORSCommand = "install ";
-					ORSCommand.append(ptr);
-
-					// If we have a map of blocks we don't need to mount data.
-					SkipDecryption = *ptr == '@';
-
-					if (!OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
-						break;
-				} else
-					LOGERR("argument error specifying zip file\n");
-			} else if (*argptr == 'w') {
-				if (len == 9) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
-						break;
-				} else if (len == 10) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
-						break;
-				}
-				// Other 'w' items are wipe_ab and wipe_package_size which are related to bricking the device remotely. We will not bother to suppor these as having TWRP probably makes "bricking" the device in this manner useless
-			} else if (*argptr == 'n') {
-				DataManager::SetValue(TW_BACKUP_NAME, gui_parse_text("{@auto_generate}"));
-				if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
-					break;
-			} else if (*argptr == 'p') {
-				Shutdown = true;
-			} else if (*argptr == 's') {
-				if (strncmp(argptr, "send_intent", strlen("send_intent")) == 0) {
-					ptr = argptr + strlen("send_intent") + 1;
-					Send_Intent = *ptr;
-				} else if (strncmp(argptr, "security", strlen("security")) == 0) {
-					LOGINFO("Security update\n");
-				} else if (strncmp(argptr, "sideload", strlen("sideload")) == 0) {
-					if (!OpenRecoveryScript::Insert_ORS_Command("sideload\n"))
-						break;
-				} else if (strncmp(argptr, "stages", strlen("stages")) == 0) {
-					LOGINFO("ignoring stages command\n");
-				}
-			} else if (*argptr == 'r') {
-				if (strncmp(argptr, "reason", strlen("reason")) == 0) {
-					ptr = argptr + strlen("reason") + 1;
-					gui_print("%s\n", ptr);
-				}
-			}
-		}
-		printf("\n");
-	}
-
-	if (crash_counter == 0) {
-		property_list(Print_Prop, NULL);
-		printf("\n");
-	} else {
-		printf("twrp.crash_counter=%d\n", crash_counter);
-	}
-
 	// Check for and run startup script if script exists
 	TWFunc::check_and_run_script("/system/bin/runatboot.sh", "boot");
 	TWFunc::check_and_run_script("/system/bin/postrecoveryboot.sh", "boot");
@@ -295,22 +176,20 @@
 	LOGINFO("Backup of TWRP ramdisk done.\n");
 #endif
 
-	Decrypt_Page(SkipDecryption, datamedia);
+	Decrypt_Page(skip_decryption, datamedia);
 
 	// Fixup the RTC clock on devices which require it
 	if (crash_counter == 0)
 		TWFunc::Fixup_Time_On_Boot();
 
 	DataManager::ReadSettingsFile();
-	PageManager::LoadLanguage(DataManager::GetStrValue("tw_language"));
-	GUIConsole::Translate_Now();
 
 	// Run any outstanding OpenRecoveryScript
 	std::string cacheDir = TWFunc::get_log_dir();
 	if (cacheDir == DATA_LOGS_DIR)
 		cacheDir = "/data/cache";
 	std::string orsFile = cacheDir + "/recovery/openrecoveryscript";
-	if ((DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 || SkipDecryption) && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(orsFile))) {
+	if ((DataManager::GetIntValue(TW_IS_ENCRYPTED) == 0 || skip_decryption) && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(orsFile))) {
 		OpenRecoveryScript::Run_OpenRecoveryScript();
 	}
 
@@ -378,23 +257,19 @@
 
 	TWFunc::Update_Log_File();
 
-	twrpAdbBuFifo *adb_bu_fifo = new twrpAdbBuFifo();
 	adb_bu_fifo->threadAdbBuFifo();
 
-	// Launch the main GUI
-	gui_start();
-
 #ifndef TW_OEM_BUILD
 	// Disable flashing of stock recovery
 	TWFunc::Disable_Stock_Recovery_Replace();
 #endif
+}
 
-	// Reboot
-	TWFunc::Update_Intent_File(Send_Intent);
-	delete adb_bu_fifo;
-	TWFunc::Update_Log_File();
+static void reboot() {
 	gui_msg(Msg("rebooting=Rebooting..."));
+	TWFunc::Update_Log_File();
 	string Reboot_Arg;
+
 	DataManager::GetValue("tw_reboot_arg", Reboot_Arg);
 	if (Reboot_Arg == "recovery")
 		TWFunc::tw_reboot(rb_recovery);
@@ -406,9 +281,86 @@
 		TWFunc::tw_reboot(rb_download);
 	else if (Reboot_Arg == "edl")
 		TWFunc::tw_reboot(rb_edl);
+	else if (Reboot_Arg == "fastboot")
+		TWFunc::tw_reboot(rb_fastboot);
 	else
 		TWFunc::tw_reboot(rb_system);
+}
+
+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);
+
+	signal(SIGPIPE, SIG_IGN);
+
+	// Handle ADB sideload
+	if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
+		property_set("ctl.stop", "adbd");
+#ifdef TW_USE_NEW_MINADBD
+		//adb_server_main(0, DEFAULT_ADB_PORT, -1); TODO fix this for android8
+		// minadbd_main();
+#else
+		adb_main(argv[2]);
+#endif
+		return 0;
+	}
+
+#ifdef RECOVERY_SDCARD_ON_DATA
+	datamedia = true;
+#endif
+
+	property_set("ro.twrp.boot", "1");
+	property_set("ro.twrp.version", TW_VERSION_STR);
+
+	time_t StartupTime = time(NULL);
+	printf("Starting TWRP %s-%s on %s (pid %d)\n", TW_VERSION_STR, TW_GIT_REVISION, ctime(&StartupTime), getpid());
+
+	// Load default values to set DataManager constants and handle ifdefs
+	DataManager::SetDefaultValues();
+	printf("Starting the UI...\n");
+	gui_init();
+
+	// Load up all the resources
+	gui_loadResources();
+
+	PageManager::LoadLanguage(DataManager::GetStrValue("tw_language"));
+	GUIConsole::Translate_Now();
+
+	startupArgs startup;
+	startup.parse(&argc, &argv);
+	twrpAdbBuFifo *adb_bu_fifo = new twrpAdbBuFifo();
+	TWFunc::Clear_Bootloader_Message();
+
+	if (startup.Get_Fastboot_Mode()) {
+		LOGINFO("starting fastboot\n");
+		gui_msg(Msg("fastboot_console_msg=Entered Fastboot mode..."));
+		if (gui_startPage("fastboot", 1, 1) != 0) {
+			LOGERR("Failed to start fastbootd page.\n");
+		}
+		delete adb_bu_fifo;
+		TWFunc::Update_Intent_File(startup.Get_Intent());
+
+		reboot();
+		return 0;
+	} else {
+		process_recovery_mode(adb_bu_fifo, startup.Should_Skip_Decryption());
+	}
+
+	// Launch the main GUI
+	gui_start();
+	delete adb_bu_fifo;
+	TWFunc::Update_Intent_File(startup.Get_Intent());
+
+	reboot();
 
 	return 0;
 }
-