diff options
Diffstat (limited to 'recovery.cpp')
-rw-r--r-- | recovery.cpp | 126 |
1 files changed, 100 insertions, 26 deletions
diff --git a/recovery.cpp b/recovery.cpp index c82844d25..654a66526 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -61,6 +61,7 @@ static const struct option OPTIONS[] = { #define LAST_LOG_FILE "/cache/recovery/last_log" +static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; @@ -74,6 +75,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; +char recovery_version[PROPERTY_VALUE_MAX+1]; /* * The recovery tool communicates with the main system through /cache files. @@ -283,6 +285,19 @@ rotate_last_logs(int max) { } } +static void +copy_logs() { + // Copy logs to cache so the system can find out what happened. + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); + chmod(LOG_FILE, 0600); + chown(LOG_FILE, 1000, 1000); // system user + chmod(LAST_LOG_FILE, 0640); + chmod(LAST_INSTALL_FILE, 0644); + sync(); +} + // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. @@ -312,14 +327,7 @@ finish_recovery(const char *send_intent) { check_and_fclose(fp, LOCALE_FILE); } - // Copy logs to cache so the system can find out what happened. - copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); - copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); - copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); - chmod(LOG_FILE, 0600); - chown(LOG_FILE, 1000, 1000); // system user - chmod(LAST_LOG_FILE, 0640); - chmod(LAST_INSTALL_FILE, 0644); + copy_logs(); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -336,22 +344,95 @@ finish_recovery(const char *send_intent) { sync(); // For good measure. } +typedef struct _saved_log_file { + char* name; + struct stat st; + unsigned char* data; + struct _saved_log_file* next; +} saved_log_file; + static int erase_volume(const char *volume) { + bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); + ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + + saved_log_file* head = NULL; + + if (is_cache) { + // If we're reformatting /cache, we load any + // "/cache/recovery/last*" files into memory, so we can restore + // them after the reformat. + + ensure_path_mounted(volume); + + DIR* d; + struct dirent* de; + d = opendir(CACHE_LOG_DIR); + if (d) { + char path[PATH_MAX]; + strcpy(path, CACHE_LOG_DIR); + strcat(path, "/"); + int path_len = strlen(path); + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "last", 4) == 0) { + saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); + strcpy(path+path_len, de->d_name); + p->name = strdup(path); + if (stat(path, &(p->st)) == 0) { + // truncate files to 512kb + if (p->st.st_size > (1 << 19)) { + p->st.st_size = 1 << 19; + } + p->data = (unsigned char*) malloc(p->st.st_size); + FILE* f = fopen(path, "rb"); + fread(p->data, 1, p->st.st_size, f); + fclose(f); + p->next = head; + head = p; + } else { + free(p); + } + } + } + closedir(d); + } else { + if (errno != ENOENT) { + printf("opendir failed: %s\n", strerror(errno)); + } + } + } + ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); + int result = format_volume(volume); + + if (is_cache) { + while (head) { + FILE* f = fopen_path(head->name, "wb"); + if (f) { + fwrite(head->data, 1, head->st.st_size, f); + fclose(f); + chmod(head->name, head->st.st_mode); + chown(head->name, head->st.st_uid, head->st.st_gid); + } + free(head->name); + free(head->data); + saved_log_file* temp = head->next; + free(head); + head = temp; + } - if (strcmp(volume, "/cache") == 0) { // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; + copy_logs(); } - return format_volume(volume); + return result; } static char* @@ -446,21 +527,17 @@ copy_sideloaded_package(const char* original_path) { static const char** prepend_title(const char* const* headers) { - const char* title[] = { "Android system recovery <" - EXPAND(RECOVERY_API_VERSION) "e>", - "", - NULL }; - // count the number of lines in our title, plus the // caller-provided headers. - int count = 0; + int count = 3; // our title has 3 lines const char* const* p; - for (p = title; *p; ++p, ++count); for (p = headers; *p; ++p, ++count); const char** new_headers = (const char**)malloc((count+1) * sizeof(char*)); const char** h = new_headers; - for (p = title; *p; ++p, ++h) *h = *p; + *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>"; + *(h++) = recovery_version; + *(h++) = ""; for (p = headers; *p; ++p, ++h) *h = *p; *h = NULL; @@ -734,10 +811,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_EXT: - // Some packages expect /cache to be mounted (eg, - // standard incremental packages expect to use /cache - // as scratch space). - ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -783,12 +856,12 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_ADB_SIDELOAD: - ensure_path_mounted(CACHE_ROOT); status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status >= 0) { if (status != INSTALL_SUCCESS) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); + copy_logs(); } else if (!ui->IsTextVisible()) { return; // reboot if logs aren't visible } else { @@ -866,7 +939,7 @@ main(int argc, char **argv) { load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); - rotate_last_logs(5); + rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; @@ -913,8 +986,7 @@ main(int argc, char **argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); - ui->Print("Warning: No file_contexts\n"); + ui->Print("Warning: No file_contexts\n"); } device->StartRecovery(); @@ -942,6 +1014,7 @@ main(int argc, char **argv) { printf("\n"); property_list(print_property, NULL); + property_get("ro.build.display.id", recovery_version, ""); printf("\n"); int status = INSTALL_SUCCESS; @@ -979,6 +1052,7 @@ main(int argc, char **argv) { } if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { + copy_logs(); ui->SetBackground(RecoveryUI::ERROR); } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { |