From 6d0d7ac051a0338c0e07e239e742b92e5ab8ea07 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 9 Jul 2013 13:34:55 -0700 Subject: recovery: preserve recovery logs across cache wipes When doing a cache wipe or a factory reset (which includes a cache wipe), save any last* log files in the /cache/recovery directory and write them back after reformatting the partition, so that wiping data doesn't lose useful log information. Change-Id: I1f52ae9131760b5e752e136645c19f71b7b166ee --- recovery.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) (limited to 'recovery.cpp') diff --git a/recovery.cpp b/recovery.cpp index b7fb616ce..82cfc3f8d 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"; @@ -342,22 +343,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* -- cgit v1.2.3