int
main(int argc, char **argv) {
    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
        adb_main(argv[2]);
        return 0;
    }

    printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));

    Device* device = make_device();
    ui = device->GetUI();

	//ui->Init();
    //ui->SetBackground(RecoveryUI::NONE);
    //load_volume_table();

	// Load default values to set DataManager constants and handle ifdefs
	DataManager_LoadDefaults();
	printf("Starting the UI...");
	gui_init();
	printf("=> Linking mtab\n");
	system("ln -s /proc/mounts /etc/mtab"); // Link mtab for mke2fs
	printf("=> Processing recovery.fstab\n");
	if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
		LOGE("Failing out of recovery due to problem with recovery.fstab.\n");
		//return -1;
	}
	PartitionManager.Output_Partition_Logging();
	// Load up all the resources
	gui_loadResources();

    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    bool just_exit = false;
	bool perform_backup = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': ui->ShowText(true); break;
        case 'x': just_exit = true; break;
        case 'n': perform_backup = true; LOGI("nandroid\n"); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

#ifdef HAVE_SELINUX
    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui->Print("Warning:  No file_contexts\n");
    }
#endif

    //device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

	// 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:
	LOGI("Backing up TWRP ramdisk...\n");
	system("injecttwrp --backup /tmp/backup_recovery_ramdisk.img");
	LOGI("Backup of TWRP ramdisk done.\n");
#endif

    int status = INSTALL_SUCCESS;

	if (perform_backup) {
		char empt[50];
		gui_console_only();
		strcpy(empt, "(Current Date)");
		DataManager_SetStrValue(TW_BACKUP_NAME, empt);
		if (OpenRecoveryScript::Backup_Command("BSDCAE") != 0)
			status = INSTALL_ERROR;
	}
	if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
    if (update_package != NULL) {
		gui_console_only();
		if (OpenRecoveryScript::Install_Command(update_package) == 0)
			status = INSTALL_SUCCESS;
		else
			status = INSTALL_ERROR;
		/*
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
		*/
    } else if (wipe_data) {
		gui_console_only();
		if (!PartitionManager.Factory_Reset()) status = INSTALL_ERROR;
		/*
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
		*/
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
		gui_console_only();
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_ERROR;  // No command specified
    }
	}

    //if (status != INSTALL_SUCCESS) ui->SetBackground(RecoveryUI::ERROR);
    if (status != INSTALL_SUCCESS /*|| ui->IsTextVisible()*/) {
		finish_recovery(NULL);
		DataManager_ReadSettingsFile();
		if (PartitionManager.Mount_By_Path("/system", false) && TWFunc::Path_Exists("/system/recovery-from-boot.p")) {
			system("mv /system/recovery-from-boot.p /system/recovery-from-boot.bak");
			ui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n");
		}
		PartitionManager.UnMount_By_Path("/system", false);
		if (DataManager_GetIntValue(TW_IS_ENCRYPTED) == 0 && OpenRecoveryScript::check_for_script_file()) {
			gui_console_only();
			if (OpenRecoveryScript::run_script_file() != 0) {
				// There was an error, boot the recovery
				gui_start();
			} else {
				usleep(2000000); // Sleep for 2 seconds before rebooting
			}
		} else
			gui_start();
		//prompt_and_wait(device);
    }

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui->Print("Rebooting...\n");
#ifdef ANDROID_RB_RESTART
    android_reboot(ANDROID_RB_RESTART, 0, 0);
#else
	reboot(RB_AUTOBOOT);
#endif
    return EXIT_SUCCESS;
}
int
main(int argc, char **argv) {
    // Recovery needs to install world-readable files, so clear umask
    // set by init
    umask(0);

    time_t start = time(NULL);

    // If these fail, there's not really anywhere to complain...
    freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
    freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);

    // If this binary is started with the single argument "--adbd",
    // instead of being the normal recovery binary, it turns into kind
    // of a stripped-down version of adbd that only supports the
    // 'sideload' command.  Note this must be a real argument, not
    // anything in the command file or bootloader control block; the
    // only way recovery should be run with this argument is when it
    // starts a copy of itself from the apply_from_adb() function.
    if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
        adb_main(argv[2]);
        return 0;
    }

    printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));

    Device* device = make_device();
    ui = device->GetUI();

	//ui->Init();
    //ui->SetBackground(RecoveryUI::NONE);
    //load_volume_table();

	// Load default values to set DataManager constants and handle ifdefs
	DataManager_LoadDefaults();
	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)) {
		LOGE("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);
    get_args(&argc, &argv);

    int previous_runs = 0;
    const char *send_intent = NULL;
    const char *update_package = NULL;
    int wipe_data = 0, wipe_cache = 0;
    bool just_exit = false;
	bool perform_backup = false;

    int arg;
    while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
        switch (arg) {
        case 'p': previous_runs = atoi(optarg); break;
        case 's': send_intent = optarg; break;
        case 'u': update_package = optarg; break;
        case 'w': wipe_data = wipe_cache = 1; break;
        case 'c': wipe_cache = 1; break;
        case 't': ui->ShowText(true); break;
        case 'x': just_exit = true; break;
        case 'n': perform_backup = true; LOGI("nandroid\n"); break;
        case '?':
            LOGE("Invalid command argument\n");
            continue;
        }
    }

#ifdef HAVE_SELINUX
    struct selinux_opt seopts[] = {
      { SELABEL_OPT_PATH, "/file_contexts" }
    };

    sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1);

    if (!sehandle) {
        fprintf(stderr, "Warning: No file_contexts\n");
        ui->Print("Warning:  No file_contexts\n");
    }
#endif

    //device->StartRecovery();

    printf("Command:");
    for (arg = 0; arg < argc; arg++) {
        printf(" \"%s\"", argv[arg]);
    }
    printf("\n");

    if (update_package) {
        // For backwards compatibility on the cache partition only, if
        // we're given an old 'root' path "CACHE:foo", change it to
        // "/cache/foo".
        if (strncmp(update_package, "CACHE:", 6) == 0) {
            int len = strlen(update_package) + 10;
            char* modified_path = (char*)malloc(len);
            strlcpy(modified_path, "/cache/", len);
            strlcat(modified_path, update_package+6, len);
            printf("(replacing path \"%s\" with \"%s\")\n",
                   update_package, modified_path);
            update_package = modified_path;
        }
    }
    printf("\n");

    property_list(print_property, NULL);
    printf("\n");

	// 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;
	LOGI("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);
	}
	LOGI("Backup of TWRP ramdisk done.\n");
#endif

    int status = INSTALL_SUCCESS;
	string ORSCommand;

	if (perform_backup) {
		char empt[50];
		gui_console_only();
		strcpy(empt, "(Current Date)");
		DataManager_SetStrValue(TW_BACKUP_NAME, empt);
		if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
			status = INSTALL_ERROR;
	}
	if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
    if (update_package != NULL) {
		ORSCommand = "install ";
		ORSCommand += update_package;
		ORSCommand += "\n";

		if (OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
			status = INSTALL_SUCCESS;
		else
			status = INSTALL_ERROR;
		/*
        status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE);
        if (status == INSTALL_SUCCESS && wipe_cache) {
            if (erase_volume("/cache")) {
                LOGE("Cache wipe (requested by package) failed.");
            }
        }
        if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
		*/
    } else if (wipe_data) {
		if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
			status = INSTALL_ERROR;
		/*
        if (device->WipeData()) status = INSTALL_ERROR;
        if (erase_volume("/data")) status = INSTALL_ERROR;
        if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
		*/
        if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
    } else if (wipe_cache) {
        if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
			status = INSTALL_ERROR;
        if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
    } else if (!just_exit) {
        status = INSTALL_ERROR;  // No command specified
    }
	}

	finish_recovery(NULL);
	// Offer to decrypt if the device is encrypted
	if (DataManager_GetIntValue(TW_IS_ENCRYPTED) != 0) {
		LOGI("Is encrypted, do decrypt page first\n");
		if (gui_startPage("decrypt") != 0) {
			LOGE("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");
			ui_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_SetIntValue("tw_busy", 1);
			if (gui_startPage("installsu") != 0) {
				LOGE("Failed to start decrypt GUI page.\n");
			}
		} else if (TWFunc::Check_su_Perms() > 0) {
			// su perms are set incorrectly
			DataManager_SetIntValue("tw_busy", 1);
			if (gui_startPage("fixsu") != 0) {
				LOGE("Failed to start decrypt GUI page.\n");
			}
		}
		sync();
		PartitionManager.UnMount_By_Path("/system", false);
	}

    // Otherwise, get ready to boot the main system...
    finish_recovery(send_intent);
    ui->Print("Rebooting...\n");
	char backup_arg_char[50];
	strcpy(backup_arg_char, DataManager_GetStrValue("tw_reboot_arg"));
	string backup_arg = backup_arg_char;
	if (backup_arg == "recovery")
		TWFunc::tw_reboot(rb_recovery);
	else if (backup_arg == "poweroff")
		TWFunc::tw_reboot(rb_poweroff);
	else if (backup_arg == "bootloader")
		TWFunc::tw_reboot(rb_bootloader);
	else if (backup_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 EXIT_SUCCESS;
}