static void partition_sdcard(const char* volume) {
    if (!can_partition(volume)) {
        ui_print("Can't partition device: %s\n", volume);
        return;
    }

    static char* ext_sizes[] = { "128M",
                                 "256M",
                                 "512M",
                                 "1024M",
                                 "2048M",
                                 "4096M",
                                 NULL };

    static char* swap_sizes[] = { "0M",
                                  "32M",
                                  "64M",
                                  "128M",
                                  "256M",
                                  NULL };

    static char* partition_types[] = { "ext3",
                                       "ext4",
                                       NULL
    };

    static char* ext_headers[] = { "Ext Size", "", NULL };
    static char* swap_headers[] = { "Swap Size", "", NULL };
    static char* fstype_headers[] = {"Partition Type", "", NULL };

    int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
    if (ext_size == GO_BACK)
        return;

    int swap_size = get_menu_selection(swap_headers, swap_sizes, 0, 0);
    if (swap_size == GO_BACK)
        return;

    int partition_type = get_menu_selection(fstype_headers, partition_types, 0, 0);
    if (partition_type == GO_BACK)
        return;

    char sddevice[256];
    Volume *vol = volume_for_path(volume);
    strcpy(sddevice, vol->device);
    // we only want the mmcblk, not the partition
    sddevice[strlen("/dev/block/mmcblkX")] = NULL;
    char cmd[PATH_MAX];
    setenv("SDPATH", sddevice, 1);
    sprintf(cmd, "sdparted -es %s -ss %s -efs %s -s", ext_sizes[ext_size], swap_sizes[swap_size], partition_types[partition_type]);
    ui_print("Partitioning SD Card... please wait...\n");
    if (0 == __system(cmd))
        ui_print("Done!\n");
    else
        ui_print("An error occured while partitioning your SD Card. Please see /tmp/recovery.log for more details.\n");
}
static void partition_sdcard(const char* volume) {
    if (!can_partition(volume)) {
        ui_print("无法分区设备: %s\n", volume);
        return;
    }

    static char* ext_sizes[] = { "128M",
                                 "256M",
                                 "512M",
                                 "1024M",
                                 "2048M",
                                 "4096M",
                                 NULL };

    static char* swap_sizes[] = { "0M",
                                  "32M",
                                  "64M",
                                  "128M",
                                  "256M",
                                  NULL };

    static char* ext_headers[] = { "Ext Size", "", NULL };
    static char* swap_headers[] = { "Swap Size", "", NULL };

    int ext_size = get_menu_selection(ext_headers, ext_sizes, 0, 0);
    if (ext_size == GO_BACK)
        return;

    int swap_size = get_menu_selection(swap_headers, swap_sizes, 0, 0);
    if (swap_size == GO_BACK)
        return;

    char sddevice[256];
    Volume *vol = volume_for_path(volume);
    strcpy(sddevice, vol->device);
    // we only want the mmcblk, not the partition
    sddevice[strlen("/dev/block/mmcblkX")] = NULL;
    char cmd[PATH_MAX];
    setenv("SDPATH", sddevice, 1);
    sprintf(cmd, "sdparted -es %s -ss %s -efs ext3 -s", ext_sizes[ext_size], swap_sizes[swap_size]);
    ui_print("正在对SD卡进行分区... 请等待...\n");
    if (0 == __system(cmd))
        ui_print("分区完成!\n");
    else
        ui_print("进行SD卡分区时发生一个未知错误。请查看 /tmp/recovery.log 获取详细信息\n");
}
void show_advanced_menu()
{
    static char* headers[] = {  "Advanced Menu",
                                "",
                                NULL
    };

    static char* list[] = { "reboot recovery",
                            "reboot to bootloader",
                            "power off",
                            "wipe dalvik cache",
                            "report error",
                            "key test",
                            "show log",
                            "partition sdcard",
                            "partition external sdcard",
                            "partition internal sdcard",
                            NULL
    };

    char bootloader_mode[PROPERTY_VALUE_MAX];
    property_get("ro.bootloader.mode", bootloader_mode, "");
    if (!strcmp(bootloader_mode, "download")) {
        list[1] = "reboot to download mode";
    }

    if (!can_partition("/sdcard")) {
        list[7] = NULL;
    }
    if (!can_partition("/external_sd")) {
        list[8] = NULL;
    }
    if (!can_partition("/emmc")) {
        list[9] = NULL;
    }

    for (;;)
    {
        int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*));
        if (chosen_item == GO_BACK)
            break;
        switch (chosen_item)
        {
            case 0:
            {
                ui_print("Rebooting recovery...\n");
                reboot_main_system(ANDROID_RB_RESTART2, 0, "recovery");
                break;
            }
            case 1:
            {
                if (!strcmp(bootloader_mode, "download")) {
                    ui_print("Rebooting to download mode...\n");
                    reboot_main_system(ANDROID_RB_RESTART2, 0, "download");
                } else {
                    ui_print("Rebooting to bootloader...\n");
                    reboot_main_system(ANDROID_RB_RESTART2, 0, "bootloader");
                }
                break;
            }
            case 2:
            {
                ui_print("Shutting down...\n");
                reboot_main_system(ANDROID_RB_POWEROFF, 0, 0);
                break;
            }
            case 3:
                if (0 != ensure_path_mounted("/data"))
                    break;
                ensure_path_mounted("/sd-ext");
                ensure_path_mounted("/cache");
                if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
                    __system("rm -r /data/dalvik-cache");
                    __system("rm -r /cache/dalvik-cache");
                    __system("rm -r /sd-ext/dalvik-cache");
                    ui_print("Dalvik Cache wiped.\n");
                }
                ensure_path_unmounted("/data");
                break;
            case 4:
                handle_failure(1);
                break;
            case 5:
            {
                ui_print("Outputting key codes.\n");
                ui_print("Go back to end debugging.\n");
                int key;
                int action;
                do
                {
                    key = ui_wait_key();
                    action = device_handle_key(key, 1);
                    ui_print("Key: %d\n", key);
                }
                while (action != GO_BACK);
                break;
            }
            case 6:
                ui_printlogtail(12);
                break;
            case 7:
                partition_sdcard("/sdcard");
                break;
            case 8:
                partition_sdcard("/external_sd");
                break;
            case 9:
                partition_sdcard("/emmc");
                break;
        }
    }
}
void show_advanced_menu()
{
    static char* headers[] = {  "Advanced Menu",
                                "",
                                NULL
                             };

    static char* list[] = { "reboot recovery",
                            "wipe dalvik cache",
                            "wipe battery stats",
                            "report error",
                            "key test",
                            "show log",
                            "fix permissions",
                            "partition sdcard",
                            "partition external sdcard",
                            "partition internal sdcard",
                            NULL
                          };

    if (!can_partition("/sdcard")) {
        list[7] = NULL;
    }
    if (!can_partition("/external_sd")) {
        list[8] = NULL;
    }
    if (!can_partition("/emmc")) {
        list[9] = NULL;
    }

    for (;;)
    {
        int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*));
        if (chosen_item == GO_BACK)
            break;
        switch (chosen_item)
        {
        case 0:
            android_reboot(ANDROID_RB_RESTART2, 0, "recovery");
            break;
        case 1:
            if (0 != ensure_path_mounted("/data"))
                break;
            ensure_path_mounted("/sd-ext");
            ensure_path_mounted("/cache");
            if (confirm_selection( "Confirm wipe?", "Yes - Wipe Dalvik Cache")) {
                __system("rm -r /data/dalvik-cache");
                __system("rm -r /cache/dalvik-cache");
                __system("rm -r /sd-ext/dalvik-cache");
                ui_print("Dalvik Cache wiped.\n");
            }
            ensure_path_unmounted("/data");
            break;
        case 2:
            if (confirm_selection( "Confirm wipe?", "Yes - Wipe Battery Stats"))
                wipe_battery_stats();
            break;
        case 3:
            handle_failure(1);
            break;
        case 4:
        {
            ui_print("Outputting key codes.\n");
            ui_print("Go back to end debugging.\n");
            int key;
            int action;
            do
            {
                key = ui_wait_key();
                action = device_handle_key(key, 1);
                ui_print("Key: %d\n", key);
            }
            while (action != GO_BACK);
            break;
        }
        case 5:
            ui_printlogtail(12);
            break;
        case 6:
            ensure_path_mounted("/system");
            ensure_path_mounted("/data");
            ui_print("Fixing permissions...\n");
            __system("fix_permissions");
            ui_print("Done!\n");
            break;
        case 7:
            partition_sdcard("/sdcard");
            break;
        case 8:
            partition_sdcard("/external_sd");
            break;
        case 9:
            partition_sdcard("/emmc");
            break;
        }
    }
}
void show_advanced_menu()
{
    static char* headers[] = {  "高级设置",
                                "",
                                NULL
    };

    static char* list[] = { "清空Dalvik Cache",
                            "发送错误报告",
                            "按键测试",
                            "显示日志",
                            "对SD卡进行分区",
                            "对外置SD卡进行分区",
                            "对内置SD卡进行分区",
                            NULL
    };

    if (!can_partition("/sdcard")) {
        list[4] = NULL;
    }
    if (!can_partition("/external_sd")) {
        list[5] = NULL;
    }
    if (!can_partition("/emmc")) {
        list[6] = NULL;
    }

    for (;;)
    {
        int chosen_item = get_filtered_menu_selection(headers, list, 0, 0, sizeof(list) / sizeof(char*));
        if (chosen_item == GO_BACK)
            break;
        switch (chosen_item)
        {
            case 0:
                if (0 != ensure_path_mounted("/data"))
                    break;
                ensure_path_mounted("/sd-ext");
                ensure_path_mounted("/cache");
                if (confirm_selection( "确定清空?", "是 - 清空Dalvik Cache")) {
                    __system("rm -r /data/dalvik-cache");
                    __system("rm -r /cache/dalvik-cache");
                    __system("rm -r /sd-ext/dalvik-cache");
                    ui_print("Dalvik Cache 已经清空!\n");
                }
                ensure_path_unmounted("/data");
                break;
            case 1:
                handle_failure(1);
                break;
            case 2:
            {
                ui_print("正在进行键位测试\n");
                ui_print("按返回结束测试.\n");
                int key;
                int action;
                do
                {
                    key = ui_wait_key();
                    action = device_handle_key(key, 1);
                    ui_print("键值: %d\n", key);
                }
                while (action != GO_BACK);
                break;
            }
            case 3:
                ui_printlogtail(12);
                break;
            case 4:
                partition_sdcard("/sdcard");
                break;
            case 5:
                partition_sdcard("/external_sd");
                break;
            case 6:
                partition_sdcard("/emmc");
                break;
        }
    }
}
void show_partition_menu()
{
    static char* headers[] = {  "Storage Management",
                                "",
                                NULL
    };

    static MountMenuEntry* mount_menu = NULL;
    static FormatMenuEntry* format_menu = NULL;

    typedef char* string;

    int i, mountable_volumes, formatable_volumes;
    int num_volumes;
    Volume* device_volumes;

    num_volumes = get_num_volumes();
    device_volumes = get_device_volumes();

    string options[255];

    if(!device_volumes)
        return;

    mountable_volumes = 0;
    formatable_volumes = 0;

    mount_menu = malloc(num_volumes * sizeof(MountMenuEntry));
    format_menu = malloc(num_volumes * sizeof(FormatMenuEntry));

    for (i = 0; i < num_volumes; ++i) {
        Volume* v = &device_volumes[i];
        if(strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) != 0 && strcmp("emmc", v->fs_type) != 0 && strcmp("bml", v->fs_type) != 0) {
			if(strcmp("datamedia", v->fs_type) != 0) {
				sprintf(&mount_menu[mountable_volumes].mount, "Mount %s", v->mount_point);
				sprintf(&mount_menu[mountable_volumes].unmount, "Unmount %s", v->mount_point);
				mount_menu[mountable_volumes].v = &device_volumes[i];
				++mountable_volumes;
			}
            if (is_safe_to_format(v->mount_point)) {
                sprintf(&format_menu[formatable_volumes].txt, "Format %s", v->mount_point);
                format_menu[formatable_volumes].v = &device_volumes[i];
                ++formatable_volumes;
            }
        }
        else if (strcmp("ramdisk", v->fs_type) != 0 && strcmp("mtd", v->fs_type) == 0 && is_safe_to_format(v->mount_point))
        {
            sprintf(&format_menu[formatable_volumes].txt, "Format %s", v->mount_point);
            format_menu[formatable_volumes].v = &device_volumes[i];
            ++formatable_volumes;
        }
    }

    static char* confirm_format  = "Confirm format?";
    static char* confirm = "Yes - Format";
    char confirm_string[255];

    for (;;) {
        for (i = 0; i < mountable_volumes; i++) {
            MountMenuEntry* e = &mount_menu[i];
            Volume* v = e->v;
            if(is_path_mounted(v->mount_point))
                options[i] = e->unmount;
            else
                options[i] = e->mount;
        }
        for (i = 0; i < formatable_volumes; i++) {
            FormatMenuEntry* e = &format_menu[i];
            options[mountable_volumes+i] = e->txt;
        }

        if (!is_data_media()) {
			options[mountable_volumes + formatable_volumes] = "Mount USB Storage";
			options[mountable_volumes + formatable_volumes + 1] = "Erase dalvik-cache";
        } else {
			options[mountable_volumes + formatable_volumes] = "Erase dalvik-cache";
			options[mountable_volumes + formatable_volumes + 1] = "Format /data and /data/media (/sdcard)";
        }
		if (!can_partition("/sdcard")) {
			options[mountable_volumes + formatable_volumes + 1 + 1] = NULL;
		}
		if (!can_partition("/external_sd")) {
			options[mountable_volumes + formatable_volumes + 1 + 1 + 1] = NULL;
		}
		if (!can_partition("/emmc")) {
			options[mountable_volumes + formatable_volumes + 1 + 1 + 1 + 1] = NULL;
		}
		options[mountable_volumes + formatable_volumes + 1 + 1 + 1 + 1 + 1] = NULL;


        int chosen_item = get_menu_selection(headers, &options, 0, 0);
        if (chosen_item == GO_BACK)
            break;
        if (chosen_item == (mountable_volumes+formatable_volumes)) {
			if (!is_data_media()) {
				show_mount_usb_storage_menu();
			} else {
				if(!confirm_selection("Confirm wipe?", "Yes - Wipe Dalvik Cache"))
					continue;
				erase_dalvik_cache(NULL);
			}
		} else if (chosen_item == (mountable_volumes+formatable_volumes + 1)) {
			if (!is_data_media()) {
				if(!confirm_selection("Confirm wipe?", "Yes - Wipe Dalvik Cache"))
					continue;
				erase_dalvik_cache(NULL);
			} else {
				if (!confirm_selection("format /data and /data/media (/sdcard)", "Yes - Format"))
					continue;
				handle_data_media_format(1);
				ui_print("Formatting /data...\n");

				if (0 != format_volume("/data"))
					ui_print("Error formatting /data!\n");
				else
					ui_print("Done.\n");

				handle_data_media_format(0);
			}
		} else if (chosen_item == (mountable_volumes+formatable_volumes + 1 + 1)) {
				partition_sdcard("/sdcard");
		} else if (chosen_item == (mountable_volumes+formatable_volumes + 1 + 1 + 1)) {
				partition_sdcard("/external_sd");
		} else if (chosen_item == (mountable_volumes+formatable_volumes + 1 + 1 + 1 + 1)) {
				partition_sdcard("/emmc");
        } else if (chosen_item < mountable_volumes) {
            MountMenuEntry* e = &mount_menu[chosen_item];
            Volume* v = e->v;

            if (is_path_mounted(v->mount_point)) {
                if (0 != ensure_path_unmounted(v->mount_point))
                    ui_print("Error unmounting %s!\n", v->mount_point);
            } else {
                if (0 != ensure_path_mounted(v->mount_point))
                    ui_print("Error mounting %s!\n",  v->mount_point);
            }
        }
        else if (chosen_item < (mountable_volumes + formatable_volumes)) {
            chosen_item = chosen_item - mountable_volumes;
            FormatMenuEntry* e = &format_menu[chosen_item];
            Volume* v = e->v;

            sprintf(confirm_string, "%s - %s", v->mount_point, confirm_format);

            if (!confirm_selection(confirm_string, confirm))
                continue;
            ui_print("Formatting %s...\n", v->mount_point);
            if (0 != format_volume(v->mount_point))
                ui_print("Error formatting %s!\n", v->mount_point);
            else
                ui_print("Done.\n");
        }
    }

    free(mount_menu);
    free(format_menu);
}