diff --git a/default_recovery_ui.c b/default_recovery_ui.c index 025ee98..3514477 100644 --- a/default_recovery_ui.c +++ b/default_recovery_ui.c @@ -27,6 +27,7 @@ char* MENU_ITEMS[] = { "reboot system now", "apply sdcard:update.zip", "wipe data/factory reset", "wipe cache partition", + "install zip from sdcard", "toggle signature verification", "toggle script asserts", NULL }; @@ -56,6 +57,9 @@ int device_handle_key(int key_code, int visible) { case KEY_ENTER: case BTN_MOUSE: return SELECT_ITEM; + case KEY_BACKSPACE: + case KEY_END: + return GO_BACK; } } diff --git a/extendedcommands.c b/extendedcommands.c index b2aacc9..4ef23f7 100644 --- a/extendedcommands.c +++ b/extendedcommands.c @@ -12,6 +12,10 @@ #include #include +#include +#include +#include + #include "bootloader.h" #include "common.h" #include "cutils/properties.h" @@ -35,5 +39,100 @@ toggle_signature_check() void toggle_script_asserts() { script_assert_enabled = !script_assert_enabled; - ui_print("Script Asserts: %s\n", signature_check_enabled ? "Enabled" : "Disabled"); + ui_print("Script Asserts: %s\n", script_assert_enabled ? "Enabled" : "Disabled"); +} + +void show_choose_zip_menu() +{ + static char* headers[] = { "Choose a zip or press POWER to return", + "", + NULL }; + + char path[PATH_MAX] = ""; + DIR *dir; + struct dirent *de; + int total = 0; + int i; + char** files; + char** list; + + 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"); + return; + } + + 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++; + } + } + + if (total==0) { + LOGE("No tar archives found\n"); + if(closedir(dir) < 0) { + LOGE("Failed to close directory /sdcard"); + return; + } + } + else { + 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("/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"); + } + } + } + } } \ No newline at end of file diff --git a/extendedcommands.h b/extendedcommands.h index 5b82960..a4d4992 100644 --- a/extendedcommands.h +++ b/extendedcommands.h @@ -2,4 +2,10 @@ extern int signature_check_enabled; extern int script_assert_enabled; void -toggle_signature_check(); \ No newline at end of file +toggle_signature_check(); + +void +toggle_script_asserts(); + +void +show_choose_zip_menu(); \ No newline at end of file diff --git a/install.c b/install.c index 3a37b4a..5768960 100644 --- a/install.c +++ b/install.c @@ -106,7 +106,7 @@ try_update_binary(const char *path, ZipArchive *zip) { const ZipEntry* binary_entry = mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); if (binary_entry == NULL) { - return INSTALL_UPDATE_BINARY_MISSING; + return INSTALL_ERROR; } char* binary = "/tmp/update_binary"; @@ -242,17 +242,21 @@ handle_update_package(const char *path, ZipArchive *zip) // Update should take the rest of the progress bar. ui_print("Installing update...\n"); - int result = try_update_binary(path, zip); - if (result == INSTALL_UPDATE_BINARY_MISSING) - { - if (register_package_root(zip, path) < 0) { - LOGE("Can't register package root\n"); - return INSTALL_ERROR; - } - const ZipEntry *script_entry; - script_entry = find_update_script(zip); - result = handle_update_script(zip, script_entry); + // Try installing via the update-script first, because we + // have more control over the asserts it may contain. + // If it does not exist, try the update-binary. + if (register_package_root(zip, path) < 0) { + LOGE("Can't register package root\n"); + return INSTALL_ERROR; } + const ZipEntry *script_entry; + script_entry = find_update_script(zip); + int result = handle_update_script(zip, script_entry); + if (result == INSTALL_UPDATE_SCRIPT_MISSING) + { + result = try_update_binary(path, zip); + } + register_package_root(NULL, NULL); // Unregister package root return result; } diff --git a/install.h b/install.h index 42c1444..3ee814b 100644 --- a/install.h +++ b/install.h @@ -19,7 +19,7 @@ #include "common.h" -enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_UPDATE_BINARY_MISSING }; +enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_UPDATE_SCRIPT_MISSING }; int install_package(const char *root_path); #endif // RECOVERY_INSTALL_H_ diff --git a/legacy.c b/legacy.c index dab06ad..cf903ce 100644 --- a/legacy.c +++ b/legacy.c @@ -90,7 +90,7 @@ handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry) char* script_data; if (read_data(zip, update_script_entry, &script_data, &script_len) < 0) { LOGE("Can't read update script\n"); - return INSTALL_ERROR; + return INSTALL_UPDATE_SCRIPT_MISSING; } /* Parse the script. Note that the script and parse tree are never freed. diff --git a/recovery.c b/recovery.c index b857610..7a12e10 100644 --- a/recovery.c +++ b/recovery.c @@ -212,7 +212,7 @@ get_args(int *argc, char ***argv) { set_bootloader_message(&boot); } -static void +void set_sdcard_update_bootloader_message() { struct bootloader_message boot; @@ -303,7 +303,7 @@ prepend_title(char** headers) { return new_headers; } -static int +int get_menu_selection(char** headers, char** items, int menu_only) { // throw away keys pressed previously, so user doesn't // accidentally trigger menu items. @@ -334,6 +334,8 @@ get_menu_selection(char** headers, char** items, int menu_only) { break; case NO_ACTION: break; + case GO_BACK: + return GO_BACK; } } else if (!menu_only) { chosen_item = action; @@ -439,6 +441,9 @@ prompt_and_wait() case ITEM_ASSERTS: toggle_script_asserts(); break; + case ITEM_INSTALL_ZIP: + show_choose_zip_menu(); + break; } } } diff --git a/recovery_ui.h b/recovery_ui.h index 1aabbdf..4d3d3e2 100644 --- a/recovery_ui.h +++ b/recovery_ui.h @@ -61,13 +61,15 @@ int device_wipe_data(); #define HIGHLIGHT_UP -2 #define HIGHLIGHT_DOWN -3 #define SELECT_ITEM -4 +#define GO_BACK -5 #define ITEM_REBOOT 0 #define ITEM_APPLY_SDCARD 1 #define ITEM_WIPE_DATA 2 #define ITEM_WIPE_CACHE 3 -#define ITEM_SIG_CHECK 4 -#define ITEM_ASSERTS 5 +#define ITEM_INSTALL_ZIP 4 +#define ITEM_SIG_CHECK 5 +#define ITEM_ASSERTS 6 // Header text to display above the main menu. extern char* MENU_HEADERS[]; @@ -75,4 +77,10 @@ extern char* MENU_HEADERS[]; // Text of menu items. extern char* MENU_ITEMS[]; +int +get_menu_selection(char** headers, char** items, int menu_only); + +void +set_sdcard_update_bootloader_message(); + #endif