summaryrefslogtreecommitdiffstats
path: root/recovery.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'recovery.cpp')
-rw-r--r--recovery.cpp146
1 files changed, 113 insertions, 33 deletions
diff --git a/recovery.cpp b/recovery.cpp
index c82844d25..e852ef87a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -56,11 +56,13 @@ static const struct option OPTIONS[] = {
{ "show_text", no_argument, NULL, 't' },
{ "just_exit", no_argument, NULL, 'x' },
{ "locale", required_argument, NULL, 'l' },
+ { "shutdown_after", no_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 },
};
#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 +76,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.
@@ -172,11 +175,11 @@ get_args(int *argc, char ***argv) {
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
if (boot.command[0] != 0 && boot.command[0] != 255) {
- LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
+ LOGI("Boot command: %.*s\n", (int)sizeof(boot.command), boot.command);
}
if (boot.status[0] != 0 && boot.status[0] != 255) {
- LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
+ LOGI("Boot status: %.*s\n", (int)sizeof(boot.status), boot.status);
}
// --- if arguments weren't supplied, look in the bootloader control block
@@ -283,6 +286,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 +328,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 +345,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 +528,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 +812,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 +857,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,19 +940,18 @@ 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;
const char *send_intent = NULL;
const char *update_package = NULL;
int wipe_data = 0, wipe_cache = 0, show_text = 0;
bool just_exit = false;
+ bool shutdown_after = false;
int arg;
while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) {
switch (arg) {
- case 'p': previous_runs = atoi(optarg); break;
case 's': send_intent = optarg; break;
case 'u': update_package = optarg; break;
case 'w': wipe_data = wipe_cache = 1; break;
@@ -886,6 +959,7 @@ main(int argc, char **argv) {
case 't': show_text = 1; break;
case 'x': just_exit = true; break;
case 'l': locale = optarg; break;
+ case 'p': shutdown_after = true; break;
case '?':
LOGE("Invalid command argument\n");
continue;
@@ -901,8 +975,8 @@ main(int argc, char **argv) {
ui = device->GetUI();
gCurrentUI = ui;
- ui->Init();
ui->SetLocale(locale);
+ ui->Init();
ui->SetBackground(RecoveryUI::NONE);
if (show_text) ui->ShowText(true);
@@ -913,8 +987,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 +1015,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 +1053,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()) {
@@ -987,7 +1062,12 @@ main(int argc, char **argv) {
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
- ui->Print("Rebooting...\n");
- android_reboot(ANDROID_RB_RESTART, 0, 0);
+ if (shutdown_after) {
+ ui->Print("Shutting down...\n");
+ property_set(ANDROID_RB_PROPERTY, "shutdown,");
+ } else {
+ ui->Print("Rebooting...\n");
+ property_set(ANDROID_RB_PROPERTY, "reboot,");
+ }
return EXIT_SUCCESS;
}