Merge branch 'cupcake'
This commit is contained in:
commit
6d12e0d6f8
1 changed files with 79 additions and 24 deletions
103
recovery.c
103
recovery.c
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -63,6 +64,48 @@ static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
||||||
* --wipe_cache - wipe cache (but not user data), then reboot
|
* --wipe_cache - wipe cache (but not user data), then reboot
|
||||||
*
|
*
|
||||||
* After completing, we remove /cache/recovery/command and reboot.
|
* After completing, we remove /cache/recovery/command and reboot.
|
||||||
|
* Arguments may also be supplied in the bootloader control block (BCB).
|
||||||
|
* These important scenarios must be safely restartable at any point:
|
||||||
|
*
|
||||||
|
* FACTORY RESET
|
||||||
|
* 1. user selects "factory reset"
|
||||||
|
* 2. main system writes "--wipe_data" to /cache/recovery/command
|
||||||
|
* 3. main system reboots into recovery
|
||||||
|
* 4. get_args() writes BCB with "boot-recovery" and "--wipe_data"
|
||||||
|
* -- after this, rebooting will restart the erase --
|
||||||
|
* 5. erase_root() reformats /data
|
||||||
|
* 6. erase_root() reformats /cache
|
||||||
|
* 7. finish_recovery() erases BCB
|
||||||
|
* -- after this, rebooting will restart the main system --
|
||||||
|
* 8. main() calls reboot() to boot main system
|
||||||
|
*
|
||||||
|
* OTA INSTALL
|
||||||
|
* 1. main system downloads OTA package to /cache/some-filename.zip
|
||||||
|
* 2. main system writes "--update_package=CACHE:some-filename.zip"
|
||||||
|
* 3. main system reboots into recovery
|
||||||
|
* 4. get_args() writes BCB with "boot-recovery" and "--update_package=..."
|
||||||
|
* -- after this, rebooting will attempt to reinstall the update --
|
||||||
|
* 5. install_package() attempts to install the update
|
||||||
|
* NOTE: the package install must itself be restartable from any point
|
||||||
|
* 6. finish_recovery() erases BCB
|
||||||
|
* -- after this, rebooting will (try to) restart the main system --
|
||||||
|
* 7. ** if install failed **
|
||||||
|
* 7a. prompt_and_wait() shows an error icon and waits for the user
|
||||||
|
* 7b; the user reboots (pulling the battery, etc) into the main system
|
||||||
|
* 8. main() calls maybe_install_firmware_update()
|
||||||
|
* ** if the update contained radio/hboot firmware **:
|
||||||
|
* 8a. m_i_f_u() writes BCB with "boot-recovery" and "--wipe_cache"
|
||||||
|
* -- after this, rebooting will reformat cache & restart main system --
|
||||||
|
* 8b. m_i_f_u() writes firmware image into raw cache partition
|
||||||
|
* 8c. m_i_f_u() writes BCB with "update-radio/hboot" and "--wipe_cache"
|
||||||
|
* -- after this, rebooting will attempt to reinstall firmware --
|
||||||
|
* 8d. bootloader tries to flash firmware
|
||||||
|
* 8e. bootloader writes BCB with "boot-recovery" (keeping "--wipe_cache")
|
||||||
|
* -- after this, rebooting will reformat cache & restart main system --
|
||||||
|
* 8f. erase_root() reformats /cache
|
||||||
|
* 8g. finish_recovery() erases BCB
|
||||||
|
* -- after this, rebooting will (try to) restart the main system --
|
||||||
|
* 9. main() calls reboot() to boot main system
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const int MAX_ARG_LENGTH = 4096;
|
static const int MAX_ARG_LENGTH = 4096;
|
||||||
|
@ -105,52 +148,64 @@ check_and_fclose(FILE *fp, const char *name) {
|
||||||
// - the contents of COMMAND_FILE (one per line)
|
// - the contents of COMMAND_FILE (one per line)
|
||||||
static void
|
static void
|
||||||
get_args(int *argc, char ***argv) {
|
get_args(int *argc, char ***argv) {
|
||||||
if (*argc > 1) return; // actual command line arguments take priority
|
|
||||||
char *argv0 = (*argv)[0];
|
|
||||||
|
|
||||||
struct bootloader_message boot;
|
struct bootloader_message boot;
|
||||||
if (!get_bootloader_message(&boot)) {
|
memset(&boot, 0, sizeof(boot));
|
||||||
if (boot.command[0] != 0 && boot.command[0] != 255) {
|
get_bootloader_message(&boot); // this may fail, leaving a zeroed structure
|
||||||
LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boot.status[0] != 0 && boot.status[0] != 255) {
|
if (boot.command[0] != 0 && boot.command[0] != 255) {
|
||||||
LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
|
LOGI("Boot command: %.*s\n", sizeof(boot.command), boot.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that from here on, a reboot goes back into recovery
|
if (boot.status[0] != 0 && boot.status[0] != 255) {
|
||||||
strcpy(boot.command, "boot-recovery");
|
LOGI("Boot status: %.*s\n", sizeof(boot.status), boot.status);
|
||||||
set_bootloader_message(&boot);
|
}
|
||||||
|
|
||||||
|
// --- if arguments weren't supplied, look in the bootloader control block
|
||||||
|
if (*argc <= 1) {
|
||||||
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
|
boot.recovery[sizeof(boot.recovery) - 1] = '\0'; // Ensure termination
|
||||||
const char *arg = strtok(boot.recovery, "\n");
|
const char *arg = strtok(boot.recovery, "\n");
|
||||||
if (arg != NULL && !strcmp(arg, "recovery")) {
|
if (arg != NULL && !strcmp(arg, "recovery")) {
|
||||||
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
|
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
|
||||||
(*argv)[0] = argv0;
|
(*argv)[0] = strdup(arg);
|
||||||
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
|
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
|
||||||
if ((arg = strtok(NULL, "\n")) == NULL) break;
|
if ((arg = strtok(NULL, "\n")) == NULL) break;
|
||||||
(*argv)[*argc] = strdup(arg);
|
(*argv)[*argc] = strdup(arg);
|
||||||
}
|
}
|
||||||
LOGI("Got arguments from boot message\n");
|
LOGI("Got arguments from boot message\n");
|
||||||
return;
|
|
||||||
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
|
} else if (boot.recovery[0] != 0 && boot.recovery[0] != 255) {
|
||||||
LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
|
LOGE("Bad boot message\n\"%.20s\"\n", boot.recovery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE *fp = fopen_root_path(COMMAND_FILE, "r");
|
// --- if that doesn't work, try the command file
|
||||||
if (fp == NULL) return;
|
if (*argc <= 1) {
|
||||||
|
FILE *fp = fopen_root_path(COMMAND_FILE, "r");
|
||||||
|
if (fp != NULL) {
|
||||||
|
char *argv0 = (*argv)[0];
|
||||||
|
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
|
||||||
|
(*argv)[0] = argv0; // use the same program name
|
||||||
|
|
||||||
*argv = (char **) malloc(sizeof(char *) * MAX_ARGS);
|
char buf[MAX_ARG_LENGTH];
|
||||||
(*argv)[0] = argv0; // use the same program name
|
for (*argc = 1; *argc < MAX_ARGS; ++*argc) {
|
||||||
|
if (!fgets(buf, sizeof(buf), fp)) break;
|
||||||
|
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
|
||||||
|
}
|
||||||
|
|
||||||
char buf[MAX_ARG_LENGTH];
|
check_and_fclose(fp, COMMAND_FILE);
|
||||||
for (*argc = 1; *argc < MAX_ARGS && fgets(buf, sizeof(buf), fp); ++*argc) {
|
LOGI("Got arguments from %s\n", COMMAND_FILE);
|
||||||
(*argv)[*argc] = strdup(strtok(buf, "\r\n")); // Strip newline.
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_and_fclose(fp, COMMAND_FILE);
|
// --> write the arguments we have back into the bootloader control block
|
||||||
LOGI("Got arguments from %s\n", COMMAND_FILE);
|
// always boot into recovery after this (until finish_recovery() is called)
|
||||||
|
strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
|
||||||
|
strlcpy(boot.recovery, "recovery\n", sizeof(boot.recovery));
|
||||||
|
int i;
|
||||||
|
for (i = 1; i < *argc; ++i) {
|
||||||
|
strlcat(boot.recovery, (*argv)[i], sizeof(boot.recovery));
|
||||||
|
strlcat(boot.recovery, "\n", sizeof(boot.recovery));
|
||||||
|
}
|
||||||
|
set_bootloader_message(&boot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue