diff --git a/default_recovery_ui.c b/default_recovery_ui.c index 2c39a78..76c39af 100644 --- a/default_recovery_ui.c +++ b/default_recovery_ui.c @@ -29,8 +29,8 @@ char* MENU_ITEMS[] = { "reboot system now", "wipe data/factory reset", "wipe cache partition", "install zip from sdcard", - "toggle signature verification", - "toggle script asserts", + "backup", + "restore", NULL }; int device_toggle_display(volatile char* key_pressed, int key_code) { diff --git a/extendedcommands.c b/extendedcommands.c index 4ef23f7..c491d84 100644 --- a/extendedcommands.c +++ b/extendedcommands.c @@ -28,6 +28,7 @@ int signature_check_enabled = 1; int script_assert_enabled = 1; +static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip"; void toggle_signature_check() @@ -42,12 +43,68 @@ void toggle_script_asserts() ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled"); } -void show_choose_zip_menu() +void install_zip(const char* packagefilepath) +{ + ui_print("\n-- Installing: %s\n", packagefilepath); + set_sdcard_update_bootloader_message(); + int status = install_package(packagefilepath); + if (status != INSTALL_SUCCESS) { + ui_set_background(BACKGROUND_ICON_ERROR); + ui_print("Installation aborted.\n"); + } else if (!ui_text_visible()) { + return; // reboot if logs aren't visible + } else { + if (firmware_update_pending()) { + ui_print("\nReboot via menu to complete\n" + "installation.\n"); + } else { + ui_print("\nInstall from sdcard complete.\n"); + } + } +} + +char* INSTALL_MENU_ITEMS[] = { "apply sdcard:update.zip", + "choose zip from sdcard", + "toggle signature verification", + "toggle script asserts", + NULL }; +#define ITEM_APPLY_SDCARD 0 +#define ITEM_CHOOSE_ZIP 1 +#define ITEM_SIG_CHECK 2 +#define ITEM_ASSERTS 3 + +void show_install_update_menu() +{ + static char* headers[] = { "Apply update from .zip file on SD card", + "", + NULL + }; + for (;;) + { + int chosen_item = get_menu_selection(headers, INSTALL_MENU_ITEMS, 0); + switch (chosen_item) + { + case ITEM_ASSERTS: + toggle_script_asserts(); + break; + case ITEM_SIG_CHECK: + toggle_signature_check(); + break; + case ITEM_APPLY_SDCARD: + install_zip(SDCARD_PACKAGE_FILE); + break; + case ITEM_CHOOSE_ZIP: + show_choose_zip_menu(); + break; + default: + return; + } + + } +} + +char* choose_file_menu(const char* directory, const char* extension, const char* headers[]) { - static char* headers[] = { "Choose a zip or press POWER to return", - "", - NULL }; - char path[PATH_MAX] = ""; DIR *dir; struct dirent *de; @@ -56,83 +113,126 @@ void show_choose_zip_menu() char** files; char** list; + dir = opendir(directory); + if (dir == NULL) { + ui_print("Couldn't open directory.\n"); + return NULL; + } + + const int extension_length = strlen(extension); + + while ((de=readdir(dir)) != NULL) { + if (de->d_name[0] != '.' && strlen(de->d_name) > extension_length && strcmp(de->d_name + strlen(de->d_name) - extension_length, extension) == 0) { + total++; + } + } + + if (total==0) { + ui_print("No files found.\n"); + if(closedir(dir) < 0) { + LOGE("Failed to close directory."); + } + return NULL; + } + + files = (char**) malloc((total+1)*sizeof(char*)); + files[total]=NULL; + + list = (char**) malloc((total+1)*sizeof(char*)); + list[total]=NULL; + + rewinddir(dir); + + i = 0; + while ((de = readdir(dir)) != NULL) { + if (de->d_name[0] != '.' && strlen(de->d_name) > extension_length && strcmp(de->d_name + strlen(de->d_name) - extension_length, extension) == 0) { + files[i] = (char*) malloc(strlen(directory)+strlen(de->d_name)+1); + strcpy(files[i], directory); + strcat(files[i], de->d_name); + + list[i] = (char*) malloc(strlen(de->d_name)+1); + strcpy(list[i], de->d_name); + + i++; + } + } + + if (closedir(dir) <0) { + LOGE("Failure closing directory."); + return NULL; + } + + int chosen_item = get_menu_selection(headers, list, 1); + static char ret[PATH_MAX]; + strcpy(ret, files[chosen_item]); + return ret; +} + +void show_choose_zip_menu() +{ if (ensure_root_path_mounted("SDCARD:") != 0) { LOGE ("Can't mount /sdcard\n"); return; } - dir = opendir("/sdcard"); - if (dir == NULL) { - LOGE("Couldn't open /sdcard"); + static char* headers[] = { "Choose a zip to apply", + "", + NULL + }; + + char* file = choose_file_menu("/sdcard/", ".zip", headers); + if (file == NULL) + return; + char sdcard_package_file[1024]; + strcpy(sdcard_package_file, "SDCARD:"); + strcat(sdcard_package_file, file + strlen("/sdcard/")); + install_zip(sdcard_package_file); +} + +void do_nandroid_backup() +{ + ui_print("Performing backup...\n"); + system("/sbin/nandroid-mobile.sh backup"); + ui_print("Backup complete.\n"); +} + +void show_nandroid_restore_menu() +{ + if (ensure_root_path_mounted("SDCARD:") != 0) { + LOGE ("Can't mount /sdcard\n"); return; } + + static char* headers[] = { "Choose an image to restore", + "", + NULL + }; - const char *extension = ".zip"; - const int extension_length = strlen(extension); - - while ((de=readdir(dir)) != NULL) { - if (de->d_name[0] != '.' && strlen(de->d_name) > extension_length && strcmp(de->d_name + strlen(de->d_name) - extension_length, extension) == 0) { - total++; - } + system("cat /proc/cmdline | sed 's/.*serialno=//' | cut -d' ' -f1 > /.deviceid"); + FILE *deviceIdFile = fopen(".deviceid", "r"); + char deviceId[256]; + if (deviceIdFile == NULL) + { + ui_print("Unable to retrieve device id.\n"); + return; } - - if (total==0) { - LOGE("No tar archives found\n"); - if(closedir(dir) < 0) { - LOGE("Failed to close directory /sdcard"); - return; - } + int readCount = fread(deviceId, 1, sizeof(deviceId), deviceIdFile); + if (readCount == 0) + { + ui_print("Unable to retrieve device id.\n"); + return; } - else { - files = (char**) malloc((total+1)*sizeof(char*)); - files[total]=NULL; + deviceId[readCount - 1] = NULL; + fclose(deviceIdFile); + char backupDirectory[PATH_MAX]; + sprintf(backupDirectory, "/sdcard/nandroid/%s/", deviceId); - list = (char**) malloc((total+1)*sizeof(char*)); - list[total]=NULL; - - rewinddir(dir); - - i = 0; - while ((de = readdir(dir)) != NULL) { - if (de->d_name[0] != '.' && strlen(de->d_name) > extension_length && strcmp(de->d_name + strlen(de->d_name) - extension_length, extension) == 0) { - files[i] = (char*) malloc(strlen("/sdcard/")+strlen(de->d_name)+1); - strcpy(files[i], "/sdcard/"); - strcat(files[i], de->d_name); - - list[i] = (char*) malloc(strlen(de->d_name)+1); - strcpy(list[i], de->d_name); - - i++; - } - } - - if (closedir(dir) <0) { - LOGE("Failure closing directory /sdcard\n"); - return; - } - - int chosen_item = get_menu_selection(headers, list, 1); - if (chosen_item >= 0 && chosen_item != GO_BACK) { - char sdcard_package_file[1024]; - strcpy(sdcard_package_file, "SDCARD:"); - strcat(sdcard_package_file, files[chosen_item] + strlen("/sdcard")); - - ui_print("\n-- Install from sdcard...\n"); - set_sdcard_update_bootloader_message(); - int status = install_package(sdcard_package_file); - if (status != INSTALL_SUCCESS) { - ui_set_background(BACKGROUND_ICON_ERROR); - ui_print("Installation aborted.\n"); - } else if (!ui_text_visible()) { - return; // reboot if logs aren't visible - } else { - if (firmware_update_pending()) { - ui_print("\nReboot via menu to complete\n" - "installation.\n"); - } else { - ui_print("\nInstall from sdcard complete.\n"); - } - } - } - } + char* file = choose_file_menu(backupDirectory, "", headers); + if (file == NULL) + return; + char* command[PATH_MAX]; + sprintf(command, "nandroid-mobile.sh restore %s", file); + ui_print("Performing restore...\n"); + system(command); + ui_print("Restore complete.\n"); } \ No newline at end of file diff --git a/extendedcommands.h b/extendedcommands.h index 2729de2..00dff0f 100644 --- a/extendedcommands.h +++ b/extendedcommands.h @@ -14,4 +14,10 @@ int get_allow_toggle_display(); int -ui_get_show_menu(); \ No newline at end of file +ui_get_show_menu(); + +void +do_nandroid_backup(); + +void +show_nandroid_restore_menu(); \ No newline at end of file diff --git a/recovery.c b/recovery.c index e398393..a88c696 100644 --- a/recovery.c +++ b/recovery.c @@ -440,14 +440,14 @@ prompt_and_wait() } } break; - case ITEM_SIG_CHECK: - toggle_signature_check(); - break; - case ITEM_ASSERTS: - toggle_script_asserts(); - break; case ITEM_INSTALL_ZIP: - show_choose_zip_menu(); + show_install_update_menu(); + break; + case ITEM_BACKUP: + do_nandroid_backup(); + break; + case ITEM_RESTORE: + show_nandroid_restore_menu(); break; } } diff --git a/recovery_ui.h b/recovery_ui.h index 4d3d3e2..2964dfc 100644 --- a/recovery_ui.h +++ b/recovery_ui.h @@ -68,8 +68,8 @@ int device_wipe_data(); #define ITEM_WIPE_DATA 2 #define ITEM_WIPE_CACHE 3 #define ITEM_INSTALL_ZIP 4 -#define ITEM_SIG_CHECK 5 -#define ITEM_ASSERTS 6 +#define ITEM_BACKUP 5 +#define ITEM_RESTORE 6 // Header text to display above the main menu. extern char* MENU_HEADERS[];