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
This commit is contained in:
parent
602c4ebd39
commit
6d0d7ac051
1 changed files with 76 additions and 2 deletions
78
recovery.cpp
78
recovery.cpp
|
@ -61,6 +61,7 @@ static const struct option OPTIONS[] = {
|
||||||
|
|
||||||
#define LAST_LOG_FILE "/cache/recovery/last_log"
|
#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 *COMMAND_FILE = "/cache/recovery/command";
|
||||||
static const char *INTENT_FILE = "/cache/recovery/intent";
|
static const char *INTENT_FILE = "/cache/recovery/intent";
|
||||||
static const char *LOG_FILE = "/cache/recovery/log";
|
static const char *LOG_FILE = "/cache/recovery/log";
|
||||||
|
@ -342,22 +343,95 @@ finish_recovery(const char *send_intent) {
|
||||||
sync(); // For good measure.
|
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
|
static int
|
||||||
erase_volume(const char *volume) {
|
erase_volume(const char *volume) {
|
||||||
|
bool is_cache = (strcmp(volume, CACHE_ROOT) == 0);
|
||||||
|
|
||||||
ui->SetBackground(RecoveryUI::ERASING);
|
ui->SetBackground(RecoveryUI::ERASING);
|
||||||
ui->SetProgressType(RecoveryUI::INDETERMINATE);
|
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);
|
ui->Print("Formatting %s...\n", volume);
|
||||||
|
|
||||||
ensure_path_unmounted(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.
|
// 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
|
// Reset the pointer so we copy from the beginning of the temp
|
||||||
// log.
|
// log.
|
||||||
tmplog_offset = 0;
|
tmplog_offset = 0;
|
||||||
|
copy_logs();
|
||||||
}
|
}
|
||||||
|
|
||||||
return format_volume(volume);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char*
|
static char*
|
||||||
|
|
Loading…
Reference in a new issue