// write fstab so we can mount in adb shell
void createFstab()
{
	FILE *fp;

	fp = fopen("/etc/fstab", "w");
	if (fp == NULL)
        LOGI("=> Can not open /etc/fstab.\n");
    else 
	{
        verifyFst();
		if (boo.mountable)      createFstabEntry(fp, &boo);
        if (sys.mountable)      createFstabEntry(fp, &sys);
		if (dat.mountable)      createFstabEntry(fp, &dat);
		if (strcmp(DataManager_GetStrValue(TW_DATA_BLK_DEVICE), "0") == 0)
			DataManager_SetStrValue(TW_DATA_BLK_DEVICE, dat.blk);
		if (DataManager_GetIntValue(TW_HAS_DATADATA) == 1)
			createFstabEntry(fp, &datdat);
        if (cac.mountable)      createFstabEntry(fp, &cac);
        if (sdcext.mountable)   createFstabEntry(fp, &sdcext);
        if (sdcint.mountable)   createFstabEntry(fp, &sdcint);
        if (sde.mountable)      createFstabEntry(fp, &sde);
        if (sp1.mountable)      createFstabEntry(fp, &sp1);
        if (sp2.mountable)      createFstabEntry(fp, &sp2);
        if (sp3.mountable)      createFstabEntry(fp, &sp3);
	}
	fclose(fp);
}
Volume* volume_for_path(const char* path) {
    char search_path[255];

	if (strcmp(path, "/sdcard") == 0) {
		if (DataManager_GetIntValue(TW_HAS_INTERNAL) == 1 && DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 1) {
			if (DataManager_GetIntValue(TW_HAS_EXTERNAL) == 0)
				ui_print("Unable to mount USB storage due to internal storage being in /data/media and no external storage available.\n");
			else
				strcpy(search_path, DataManager_GetStrValue(TW_EXTERNAL_MOUNT));
		} else
			strcpy(search_path, DataManager_GetCurrentStorageMount());
	} else
		strcpy(search_path, path);

	int i;
    for (i = 0; i < num_volumes; ++i) {
        Volume* v = device_volumes+i;
        int len = strlen(v->mount_point);
        if (strncmp(search_path, v->mount_point, len) == 0 &&
            (search_path[len] == '\0' || search_path[len] == '/')) {
            return v;
        }
    }
    return NULL;
}
struct dInfo* findDeviceByLabel(const char* label)
{
    if (!label)                             return NULL;
    if (strcmp(label, "system") == 0)       return &sys;
    if (strcmp(label, "userdata") == 0)     return &dat;
    if (strcmp(label, "data") == 0)         return &dat;
    if (strcmp(label, "boot") == 0)         return &boo;
    if (strcmp(label, "recovery") == 0)     return &rec;
    if (strcmp(label, "cache") == 0)        return &cac;
    if (strcmp(label, "sd-ext") == 0)       return &sde;
	if (strcmp(label, "and-sec") == 0)      return &ase;
	if (strcmp(label, "datadata") == 0) {
		DataManager_SetIntValue(TW_HAS_DATADATA, 1);
		return &datdat;
	}

    // New sdcard methods
	if (DataManager_GetIntValue(TW_HAS_INTERNAL) == 1) {
		if (strcmp(label, DataManager_GetStrValue(TW_EXTERNAL_LABEL)) == 0)      return &sdcext;
		if (strcmp(label, DataManager_GetStrValue(TW_INTERNAL_LABEL)) == 0)      return &sdcint;
		if (strcmp(label, "sdcard") == 0) {
			if (DataManager_GetIntValue(TW_USE_EXTERNAL_STORAGE) == 0) {
				return &sdcint;
			} else {
				return &sdcext;
			}
			return 0;
		}
	} else
		if (strcmp(label, DataManager_GetStrValue(TW_EXTERNAL_LABEL)) == 0)       return &sdcext;

    // Special Partitions (such as WiMAX, efs, and PDS)
    if (strcmp(label, EXPAND(SP1_NAME)) == 0)       return &sp1;
    if (strcmp(label, EXPAND(SP2_NAME)) == 0)       return &sp2;
    if (strcmp(label, EXPAND(SP3_NAME)) == 0)       return &sp3;

    return NULL;
}
int decrypt_device(void)
{
#ifdef TW_INCLUDE_CRYPTO
	int ret_val, password_len;
	char crypto_blkdev[255], password[255];
	size_t result;

	strcpy(password, DataManager_GetStrValue(TW_CRYPTO_PASSWORD));
	property_set("ro.crypto.state", "encrypted");
	property_set("ro.crypto.fs_type", CRYPTO_FS_TYPE);
	property_set("ro.crypto.fs_real_blkdev", CRYPTO_REAL_BLKDEV);
	property_set("ro.crypto.fs_mnt_point", CRYPTO_MNT_POINT);
	property_set("ro.crypto.fs_options", CRYPTO_FS_OPTIONS);
	property_set("ro.crypto.fs_flags", CRYPTO_FS_FLAGS);
	property_set("ro.crypto.keyfile.userdata", CRYPTO_KEY_LOC);
	if (cryptfs_check_passwd(password) != 0) {
		LOGE("Failed to decrypt data\n");
		return -1;
	}
	property_get("ro.crypto.fs_crypto_blkdev", crypto_blkdev, "error");
	if (strcmp(crypto_blkdev, "error") == 0) {
		LOGE("Error retrieving decrypted data block device.\n");
	} else {
		DataManager_SetStrValue(TW_DATA_BLK_DEVICE, dat.blk);
		DataManager_SetIntValue(TW_IS_DECRYPTED, 1);
		strcpy(dat.blk, crypto_blkdev);
		LOGI("Data successfully decrypted, new block device: '%s'\n", crypto_blkdev);
		// Sleep for a bit so that the device will be ready
		sleep(1);
		update_system_details();
	}
	return 0;
#else
	LOGE("No crypto support was compiled into this build.\n");
	return -1;
#endif
}
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;
}
Beispiel #6
0
void
set_restore_files()
{
    const char* nan_dir = DataManager_GetStrValue("_restore");

    // Start with the default values
    int restore_system = -1;
    int restore_data = -1;
    int restore_cache = -1;
    int restore_recovery = -1;
    int restore_boot = -1;
    int restore_andsec = -1;
    int restore_sdext = -1;
    int restore_sp1 = -1;
    int restore_sp2 = -1;
    int restore_sp3 = -1;

    DIR* d;
    d = opendir(nan_dir);
    if (d == NULL)
    {
        LOGE("error opening %s\n", nan_dir);
        return;
    }

    struct dirent* de;
    while ((de = readdir(d)) != NULL)
    {
        // Strip off three components
        char str[256];
        char* label;
        char* fstype = NULL;
        char* extn = NULL;
        char* ptr;
        struct dInfo* dev = NULL;

        strcpy(str, de->d_name);
        label = str;
        ptr = label;
        while (*ptr && *ptr != '.')     ptr++;
        if (*ptr == '.')
        {
            *ptr = 0x00;
            ptr++;
            fstype = ptr;
        }
        while (*ptr && *ptr != '.')     ptr++;
        if (*ptr == '.')
        {
            *ptr = 0x00;
            ptr++;
            extn = ptr;
        }

        if (extn == NULL || strcmp(extn, "win") != 0)   continue;

        dev = findDeviceByLabel(label);
        if (dev == NULL)
        {
            LOGE(" Unable to locate device by label\n");
            continue;
        }

        strncpy(dev->fnm, de->d_name, 256);
        dev->fnm[255] = '\0';

        // Now, we just need to find the correct label
        if (dev == &sys)        restore_system = 1;
        if (dev == &dat)        restore_data = 1;
        if (dev == &boo)        restore_boot = 1;
        if (dev == &rec)        restore_recovery = 1;
        if (dev == &cac)        restore_cache = 1;
        if (dev == &sde)        restore_sdext = 1;
        if (dev == &sp1)        restore_sp1 = 1;
        if (dev == &sp2)        restore_sp2 = 1;
        if (dev == &sp3)        restore_sp3 = 1;
        if (dev == &ase)        restore_andsec = 1;
    }
    closedir(d);

    // Set the final values
    DataManager_SetIntValue(VAR_RESTORE_SYSTEM_VAR, restore_system);
    DataManager_SetIntValue(VAR_RESTORE_DATA_VAR, restore_data);
    DataManager_SetIntValue(VAR_RESTORE_CACHE_VAR, restore_cache);
    DataManager_SetIntValue(VAR_RESTORE_RECOVERY_VAR, restore_recovery);
    DataManager_SetIntValue(VAR_RESTORE_BOOT_VAR, restore_boot);
    DataManager_SetIntValue(VAR_RESTORE_ANDSEC_VAR, restore_andsec);
    DataManager_SetIntValue(VAR_RESTORE_SDEXT_VAR, restore_sdext);
    DataManager_SetIntValue(VAR_RESTORE_SP1_VAR, restore_sp1);
    DataManager_SetIntValue(VAR_RESTORE_SP2_VAR, restore_sp2);
    DataManager_SetIntValue(VAR_RESTORE_SP3_VAR, restore_sp3);

    return;
}
Beispiel #7
0
int
nandroid_rest_exe()
{
    SetDataState("", "", 0, 0);

    const char* nan_dir = DataManager_GetStrValue("phx_restore");

    if (ensure_path_mounted(SDCARD_ROOT) != 0) {
        ui_print("-- Could not mount: %s.\n-- Aborting.\n",SDCARD_ROOT);
        return 1;
    }

    int total = 0;
    total += (DataManager_GetIntValue(VAR_RESTORE_SYSTEM_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_DATA_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_CACHE_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_RECOVERY_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_SP1_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_SP2_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_SP3_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_BOOT_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_ANDSEC_VAR) == 1 ? 1 : 0);
    total += (DataManager_GetIntValue(VAR_RESTORE_SDEXT_VAR) == 1 ? 1 : 0);

    float sections = 1.0 / total;

    time_t rStart, rStop;
    time(&rStart);
    ui_print("\n[RESTORE STARTED]\n\n");
    if (DataManager_GetIntValue(VAR_RESTORE_SYSTEM_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(sys,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_DATA_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(dat,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_BOOT_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(boo,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_RECOVERY_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(rec,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_CACHE_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(cac,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_SP1_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(sp1,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_SP2_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(sp2,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_SP3_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(sp3,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_ANDSEC_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(ase,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    if (DataManager_GetIntValue(VAR_RESTORE_SDEXT_VAR) == 1) {
        ui_show_progress(sections, 150);
        if (phx_restore(sde,nan_dir) == 1) {
            ui_print("-- Error occured, check recovery.log. Aborting.\n");
            SetDataState("Restore failed", "", 1, 1);
            return 1;
        }
    }
    time(&rStop);
    ui_print("[RESTORE COMPLETED IN %d SECONDS]\n\n",(int)difftime(rStop,rStart));
    __system("sync");
    LOGI("=> Let's update filesystem types.\n");
    verifyFst();
    LOGI("=> And update our fstab also.\n");
    createFstab();
    SetDataState("Restore Succeeded", "", 0, 1);
    return 0;
}
void twrp_themes_menu()
{
    const char* MENU_THEMES_HEADERS[] = {  "twrp Theme Chooser",
    								   	   "Taste tEh Rainbow:",
                                           NULL };
    
	char* MENU_THEMES[] =       { 	"[RESTART MENU AND APPLY THEME]",
									checkTheme(TW_THEME),
									checkTheme(CM_THEME),
									checkTheme(RED_THEME),
									checkTheme(GOOGLE_THEME),
									checkTheme(JF_THEME),
									checkTheme(HTC_THEME),
									checkTheme(FABULOUS_THEME),
									checkTheme(PURPLE_SHIFT),
									checkTheme(GREYBALLER_THEME),
									checkTheme(TRIPPY_THEME),
									checkTheme(SHIFTY_BASTARD),
									checkTheme(MYN_WARM),
									"<-- Back To twrp Settings",
									NULL };

    char** headers = prepend_title(MENU_THEMES_HEADERS);
    
    inc_menu_loc(THEMES_BACK);
    for (;;)
    {
        int chosen_item = get_menu_selection(headers, MENU_THEMES, 0, 0);
        switch (chosen_item)
        {
            case THEME_REBOOT_RECOVERY:
				set_theme(DataManager_GetStrValue(TW_COLOR_THEME_VAR));
				go_home = 1;
				go_restart = 1;
                break;
            case TW_THEME:
            	DataManager_SetIntValue(TW_COLOR_THEME_VAR, 0);
                break;
            case CM_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 1);
                break;
            case RED_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 2);
                break;
            case GOOGLE_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 3);
                break;
            case JF_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 4);
                break;
            case HTC_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 5);
                break;
            case FABULOUS_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 6);
                break;
			case PURPLE_SHIFT:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 7);
                break;
			case GREYBALLER_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 8);
                break;
			case TRIPPY_THEME:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 9);
                break;
			case SHIFTY_BASTARD:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 10);
                break;
			case MYN_WARM:
                DataManager_SetIntValue(TW_COLOR_THEME_VAR, 11);
                break;
            case THEMES_BACK:
            	dec_menu_loc();
            	return;
        }
        if (go_home) {
        	dec_menu_loc();
	        return;
	    }
        break;
    }
	ui_end_menu();
    dec_menu_loc();
    twrp_themes_menu();
}
int getLocations()
{
    // This decides if a partition can be mounted and appears in the fstab
    sys.mountable = 1;
    dat.mountable = 1;
	datdat.mountable = 1;
    cac.mountable = 1;
    sde.mountable = 1;
//    boo.mountable = 1;        // Boot is detected earlier
    rec.mountable = 0;
    sdcext.mountable = 1;
    sdcint.mountable = 1;
    ase.mountable = 0;
    sp1.mountable = SP1_MOUNTABLE;
    sp2.mountable = SP2_MOUNTABLE;
    sp3.mountable = SP3_MOUNTABLE;

	sys.is_sub_partition = 0;
    dat.is_sub_partition = 0;
	datdat.is_sub_partition = 1;
    cac.is_sub_partition = 0;
    sde.is_sub_partition = 0;
    boo.is_sub_partition = 0;
    rec.is_sub_partition = 0;
    sdcext.is_sub_partition = 0;
    sdcint.is_sub_partition = 0;
    ase.is_sub_partition = 0;
    sp1.is_sub_partition = 0;
    sp2.is_sub_partition = 0;
    sp3.is_sub_partition = 0;

    // This decides how we backup/restore a block
    sys.backup = files;
    dat.backup = files;
	datdat.backup = files;
    cac.backup = files;
    sde.backup = files;
    boo.backup = image;
    rec.backup = image;
    sdcext.backup = none;
    sdcint.backup = none;
    ase.backup = files;
    sp1.backup = SP1_BACKUP_METHOD;
    sp2.backup = SP2_BACKUP_METHOD;
    sp3.backup = SP3_BACKUP_METHOD;

	sys.is_encrypted = 0;
    dat.is_encrypted = 0;
	datdat.is_encrypted = 0;
    cac.is_encrypted = 0;
    sde.is_encrypted = 0;
    boo.is_encrypted = 0;
    rec.is_encrypted = 0;
    sdcext.is_encrypted = 0;
    sdcint.is_encrypted = 0;
    ase.is_encrypted = 0;
    sp1.is_encrypted = 0;
    sp2.is_encrypted = 0;
    sp3.is_encrypted = 0;

    if (getLocationsViaProc("emmc") != 0 && getLocationsViaProc("mtd") != 0 && getLocationsViafstab() != 0)
    {
        LOGE("E: Unable to get device locations.\n");
        return -1;
    }

    // Handle .android_secure
	char path[255];
	if (DataManager_GetIntValue(TW_HAS_INTERNAL)) {
		sprintf(ase.dev, "%s/.android_secure", DataManager_GetSettingsStoragePath());
		strcpy(ase.blk, DataManager_GetSettingsStoragePath());
	} else {
		sprintf(ase.dev, "%s/.android_secure", DataManager_GetStrValue(TW_EXTERNAL_PATH));
		strcpy(ase.blk, DataManager_GetStrValue(TW_EXTERNAL_PATH));
	}
    strcpy(ase.mnt, ".android_secure");
    strcpy(ase.fst, "vfat");

    if (strlen(sdcext.blk) > 0)
    {
        int tmpInt;
        char tmpBase[50];
        char tmpWildCard[50];
    
        // We make the base via sdcard block
        strcpy(sde.mnt, "sd-ext");
        strcpy(tmpBase, sdcext.blk);
        tmpBase[strlen(tmpBase)-1] = '\0';
        sprintf(tmpWildCard,"%s%%d",tmpBase);
        sscanf(sdcext.blk, tmpWildCard, &tmpInt); // sdcard block used as sd-ext base
        sprintf(sde.blk, "%s%d",tmpBase, tmpInt+1);
    }

    get_device_id();

	update_system_details();

    // Now, let's update the data manager...
    DataManager_SetIntValue("tw_boot_is_mountable", boo.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_system_is_mountable", sys.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_data_is_mountable", dat.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_cache_is_mountable", cac.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sdcext_is_mountable", sdcext.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sdcint_is_mountable", sdcint.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sd-ext_is_mountable", sde.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sp1_is_mountable", sp1.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sp2_is_mountable", sp2.mountable ? 1 : 0);
    DataManager_SetIntValue("tw_sp3_is_mountable", sp3.mountable ? 1 : 0);

    listMntInfo(&boo, "boot");
    listMntInfo(&sys, "system");
    listMntInfo(&dat, "data");
	if (DataManager_GetIntValue(TW_HAS_DATADATA) == 1)
		listMntInfo(&datdat, "datadata");
    listMntInfo(&cac, "cache");
    listMntInfo(&rec, "recovery");
    listMntInfo(&sdcext, "sdcext");
    listMntInfo(&sdcint, "sdcint");
    listMntInfo(&sde, "sd-ext");
	listMntInfo(&ase, "android_secure");
    listMntInfo(&sp1, "special 1");
    listMntInfo(&sp2, "special 2");
    listMntInfo(&sp3, "special 3");
    return 0;
}
void updateMntUsedSize(struct dInfo* mMnt)
{
	char path[512];

	if (strcmp(mMnt->mnt, ".android_secure") == 0)
    {
		// android_secure is a little different - we mount sdcard and use du to figure out how much space is being taken up by android_secure

		if (DataManager_GetIntValue(TW_HAS_INTERNAL)) {
			// We can ignore any error from this, it doesn't matter
			tw_mount(sdcint);
		} else {
			// We can ignore any error from this, it doesn't matter
			tw_mount(sdcext);
		}
		mMnt->used = getUsedSizeViaDu(mMnt->dev);
		mMnt->sze = mMnt->used;
		mMnt->bsze = mMnt->used;
        return;
	}

    struct statfs st;
    int mounted;

    if (!mMnt->mountable)
    {
        // Since this partition isn't mountable, we're going to mark it's used size as it's standard size
        mMnt->used = mMnt->sze;
		mMnt->bsze = mMnt->used;
        return;
    }

    mounted = tw_isMounted(*mMnt);
    if (!mounted)
    {
        if (tw_mount(*mMnt)) {
			return;
		}
    }

	if (mMnt->sze == 0) // We weren't able to get the size earlier, try another method
		getSizeViaDf(mMnt);

    sprintf(path, "/%s/.", mMnt->mnt);
    if (statfs(path, &st) != 0)
    {
        
		if (strncmp(path, "/sd-ext", 7) == 0)
			return;
		if (DataManager_GetIntValue(TW_HAS_DUAL_STORAGE)) {
			char external_mount_point[255];
			memset(external_mount_point, 0, sizeof(external_mount_point));
			sprintf(external_mount_point, "/%s/.", DataManager_GetStrValue(TW_EXTERNAL_PATH));
			if (strcmp(path, external_mount_point) == 0)
				return; // This prevents an error from showing on devices that have internal and external storage, but there is no sdcard installed.
		}
		LOGE("Unable to stat '%s'\n", path);
        return;
    }

    mMnt->used = ((st.f_blocks - st.f_bfree) * st.f_bsize);

	if (DataManager_GetIntValue(TW_HAS_DATA_MEDIA) == 1 && strcmp(mMnt->blk, dat.blk) == 0) {
		LOGI("Device has /data/media\n");
		unsigned long long data_used, data_media_used, actual_data;
		data_used = getUsedSizeViaDu("/data/");
		LOGI("Total used space on /data is: %llu\n", data_used);
		data_media_used = getUsedSizeViaDu("/data/media/");
		LOGI("Total in /data/media is: %llu\n", data_media_used);
		actual_data = data_used - data_media_used;
		LOGI("Actual data used: %llu\n", actual_data);
		mMnt->bsze = actual_data;
	} else
		mMnt->bsze = mMnt->used;

    if (!mounted)   tw_unmount(*mMnt);
    return;
}