Merge tag 'android-5.1.0_r1' of https://android.googlesource.com/platform/bootable/recovery into aosp
Android 5.1.0 release 1 Conflicts: minui/graphics_fbdev.c recovery.cpp Change-Id: Iff8a34fa59d93fb1165e06fef1fafd50292324f0
This commit is contained in:
+7
-1
@@ -34,6 +34,7 @@ on init
|
||||
chmod 0775 /tmp
|
||||
|
||||
write /proc/sys/kernel/panic_on_oops 1
|
||||
write /proc/sys/vm/max_map_count 1000000
|
||||
|
||||
on fs
|
||||
mount pstore pstore /sys/fs/pstore
|
||||
@@ -51,7 +52,6 @@ on fs
|
||||
write /sys/class/android_usb/android0/iProduct ${ro.product.model}
|
||||
write /sys/class/android_usb/android0/iSerial ${ro.serialno}
|
||||
|
||||
|
||||
on boot
|
||||
ifup lo
|
||||
hostname localhost
|
||||
@@ -63,6 +63,9 @@ on boot
|
||||
on load_all_props_action
|
||||
load_all_props
|
||||
|
||||
on firmware_mounts_complete
|
||||
rm /dev/.booting
|
||||
|
||||
# Mount filesystems and start core system services.
|
||||
on late-init
|
||||
trigger early-fs
|
||||
@@ -75,6 +78,9 @@ on late-init
|
||||
# issued fs triggers have completed.
|
||||
trigger load_all_props_action
|
||||
|
||||
# Remove a file to wake up anything waiting for firmware
|
||||
trigger firmware_mounts_complete
|
||||
|
||||
trigger early-boot
|
||||
trigger boot
|
||||
|
||||
|
||||
+102
-167
@@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/klog.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
@@ -33,11 +34,7 @@
|
||||
#include "bootloader.h"
|
||||
#include "common.h"
|
||||
#include "cutils/properties.h"
|
||||
#ifdef ANDROID_RB_RESTART
|
||||
#include "cutils/android_reboot.h"
|
||||
#else
|
||||
#include <sys/reboot.h>
|
||||
#endif
|
||||
#include "install.h"
|
||||
#include "minui/minui.h"
|
||||
#include "minzip/DirUtil.h"
|
||||
@@ -52,20 +49,8 @@ extern "C" {
|
||||
#include "fuse_sdcard_provider.h"
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
#include "data.h"
|
||||
#include "gui/gui.h"
|
||||
}
|
||||
#include "partitions.hpp"
|
||||
#include "variables.h"
|
||||
#include "openrecoveryscript.hpp"
|
||||
#include "twrp-functions.hpp"
|
||||
|
||||
TWPartitionManager PartitionManager;
|
||||
|
||||
struct selabel_handle *sehandle;
|
||||
|
||||
|
||||
static const struct option OPTIONS[] = {
|
||||
{ "send_intent", required_argument, NULL, 's' },
|
||||
{ "update_package", required_argument, NULL, 'u' },
|
||||
@@ -92,9 +77,14 @@ static const char *CACHE_ROOT = "/cache";
|
||||
static const char *SDCARD_ROOT = "/sdcard";
|
||||
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
|
||||
static const char *TEMPORARY_INSTALL_FILE = "/tmp/last_install";
|
||||
static const char *LAST_KMSG_FILE = "/cache/recovery/last_kmsg";
|
||||
#define KLOG_DEFAULT_LEN (64 * 1024)
|
||||
|
||||
#define KEEP_LOG_COUNT 10
|
||||
|
||||
// Number of lines per page when displaying a file on screen
|
||||
#define LINES_PER_PAGE 30
|
||||
|
||||
RecoveryUI* ui = NULL;
|
||||
char* locale = NULL;
|
||||
char recovery_version[PROPERTY_VALUE_MAX+1];
|
||||
@@ -275,8 +265,46 @@ set_sdcard_update_bootloader_message() {
|
||||
set_bootloader_message(&boot);
|
||||
}
|
||||
|
||||
// read from kernel log into buffer and write out to file
|
||||
static void
|
||||
save_kernel_log(const char *destination) {
|
||||
int n;
|
||||
char *buffer;
|
||||
int klog_buf_len;
|
||||
FILE *log;
|
||||
|
||||
klog_buf_len = klogctl(KLOG_SIZE_BUFFER, 0, 0);
|
||||
if (klog_buf_len <= 0) {
|
||||
LOGE("Error getting klog size (%s), using default\n", strerror(errno));
|
||||
klog_buf_len = KLOG_DEFAULT_LEN;
|
||||
}
|
||||
|
||||
buffer = (char *)malloc(klog_buf_len);
|
||||
if (!buffer) {
|
||||
LOGE("Can't alloc %d bytes for klog buffer\n", klog_buf_len);
|
||||
return;
|
||||
}
|
||||
|
||||
n = klogctl(KLOG_READ_ALL, buffer, klog_buf_len);
|
||||
if (n < 0) {
|
||||
LOGE("Error in reading klog (%s)\n", strerror(errno));
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
log = fopen_path(destination, "w");
|
||||
if (log == NULL) {
|
||||
LOGE("Can't open %s\n", destination);
|
||||
free(buffer);
|
||||
return;
|
||||
}
|
||||
fwrite(buffer, n, 1, log);
|
||||
check_and_fclose(log, destination);
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
// How much of the temp log we have copied to the copy in cache.
|
||||
//static long tmplog_offset = 0;
|
||||
static long tmplog_offset = 0;
|
||||
|
||||
static void
|
||||
copy_log_file(const char* source, const char* destination, int append) {
|
||||
@@ -322,8 +350,11 @@ copy_logs() {
|
||||
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);
|
||||
save_kernel_log(LAST_KMSG_FILE);
|
||||
chmod(LOG_FILE, 0600);
|
||||
chown(LOG_FILE, 1000, 1000); // system user
|
||||
chmod(LAST_KMSG_FILE, 0600);
|
||||
chown(LAST_KMSG_FILE, 1000, 1000); // system user
|
||||
chmod(LAST_LOG_FILE, 0640);
|
||||
chmod(LAST_INSTALL_FILE, 0644);
|
||||
sync();
|
||||
@@ -697,29 +728,71 @@ static void file_to_ui(const char* fn) {
|
||||
}
|
||||
char line[1024];
|
||||
int ct = 0;
|
||||
int key = 0;
|
||||
redirect_stdio("/dev/null");
|
||||
while(fgets(line, sizeof(line), fp) != NULL) {
|
||||
ui->Print("%s", line);
|
||||
ct++;
|
||||
if (ct % 30 == 0) {
|
||||
if (ct % LINES_PER_PAGE == 0) {
|
||||
// give the user time to glance at the entries
|
||||
ui->WaitKey();
|
||||
key = ui->WaitKey();
|
||||
|
||||
if (key == KEY_POWER) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (key == KEY_VOLUMEUP) {
|
||||
// Go back by seeking to the beginning and dumping ct - n
|
||||
// lines. It's ugly, but this way we don't need to store
|
||||
// the previous offsets. The files we're dumping here aren't
|
||||
// expected to be very large.
|
||||
int i;
|
||||
|
||||
ct -= 2 * LINES_PER_PAGE;
|
||||
if (ct < 0) {
|
||||
ct = 0;
|
||||
}
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
for (i = 0; i < ct; i++) {
|
||||
fgets(line, sizeof(line), fp);
|
||||
}
|
||||
ui->Print("^^^^^^^^^^\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the user didn't abort, then give the user time to glance at
|
||||
// the end of the log, sorry, no rewind here
|
||||
if (key != KEY_POWER) {
|
||||
ui->Print("\n--END-- (press any key)\n");
|
||||
ui->WaitKey();
|
||||
}
|
||||
|
||||
redirect_stdio(TEMPORARY_LOG_FILE);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void choose_recovery_file(Device* device) {
|
||||
int i;
|
||||
unsigned int i;
|
||||
unsigned int n;
|
||||
static const char** title_headers = NULL;
|
||||
char *filename;
|
||||
const char* headers[] = { "Select file to view",
|
||||
"",
|
||||
NULL };
|
||||
char* entries[KEEP_LOG_COUNT + 2];
|
||||
// "Go back" + LAST_KMSG_FILE + KEEP_LOG_COUNT + terminating NULL entry
|
||||
char* entries[KEEP_LOG_COUNT + 3];
|
||||
memset(entries, 0, sizeof(entries));
|
||||
|
||||
n = 0;
|
||||
entries[n++] = strdup("Go back");
|
||||
|
||||
// Add kernel kmsg file if available
|
||||
if ((ensure_path_mounted(LAST_KMSG_FILE) == 0) && (access(LAST_KMSG_FILE, R_OK) == 0)) {
|
||||
entries[n++] = strdup(LAST_KMSG_FILE);
|
||||
}
|
||||
|
||||
// Add LAST_LOG_FILE + LAST_LOG_FILE.x
|
||||
for (i = 0; i < KEEP_LOG_COUNT; i++) {
|
||||
char *filename;
|
||||
if (asprintf(&filename, (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i) == -1) {
|
||||
@@ -728,13 +801,12 @@ static void choose_recovery_file(Device* device) {
|
||||
}
|
||||
if ((ensure_path_mounted(filename) != 0) || (access(filename, R_OK) == -1)) {
|
||||
free(filename);
|
||||
entries[i+1] = NULL;
|
||||
entries[n++] = NULL;
|
||||
break;
|
||||
}
|
||||
entries[i+1] = filename;
|
||||
entries[n++] = filename;
|
||||
}
|
||||
|
||||
entries[0] = strdup("Go back");
|
||||
title_headers = prepend_title((const char**)headers);
|
||||
|
||||
while(1) {
|
||||
@@ -743,7 +815,7 @@ static void choose_recovery_file(Device* device) {
|
||||
file_to_ui(entries[chosen_item]);
|
||||
}
|
||||
|
||||
for (i = 0; i < KEEP_LOG_COUNT + 1; i++) {
|
||||
for (i = 0; i < (sizeof(entries) / sizeof(*entries)); i++) {
|
||||
free(entries[i]);
|
||||
}
|
||||
}
|
||||
@@ -909,10 +981,6 @@ ui_print(const char* format, ...) {
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
// Recovery needs to install world-readable files, so clear umask
|
||||
// set by init
|
||||
umask(0);
|
||||
|
||||
time_t start = time(NULL);
|
||||
|
||||
redirect_stdio(TEMPORARY_LOG_FILE);
|
||||
@@ -924,41 +992,15 @@ main(int argc, char **argv) {
|
||||
// anything in the command file or bootloader control block; the
|
||||
// only way recovery should be run with this argument is when it
|
||||
// starts a copy of itself from the apply_from_adb() function.
|
||||
if (argc == 3 && strcmp(argv[1], "--adbd") == 0) {
|
||||
adb_main(argv[2]);
|
||||
if (argc == 2 && strcmp(argv[1], "--adbd") == 0) {
|
||||
adb_main();
|
||||
return 0;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
printf("Starting TWRP %s on %s", TW_VERSION_STR, ctime(&start));
|
||||
|
||||
Device* device = make_device();
|
||||
ui = device->GetUI();
|
||||
|
||||
//ui->Init();
|
||||
//ui->SetBackground(RecoveryUI::NONE);
|
||||
//load_volume_table();
|
||||
|
||||
// Load default values to set DataManager constants and handle ifdefs
|
||||
DataManager_LoadDefaults();
|
||||
printf("Starting the UI...");
|
||||
gui_init();
|
||||
printf("=> Linking mtab\n");
|
||||
symlink("/proc/mounts", "/etc/mtab");
|
||||
printf("=> Processing recovery.fstab\n");
|
||||
if (!PartitionManager.Process_Fstab("/etc/recovery.fstab", 1)) {
|
||||
LOGE("Failing out of recovery due to problem with recovery.fstab.\n");
|
||||
//return -1;
|
||||
}
|
||||
PartitionManager.Output_Partition_Logging();
|
||||
// Load up all the resources
|
||||
gui_loadResources();
|
||||
|
||||
PartitionManager.Mount_By_Path("/cache", true);
|
||||
printf("Starting recovery (pid %d) on %s", getpid(), ctime(&start));
|
||||
|
||||
load_volume_table();
|
||||
ensure_path_mounted(LAST_LOG_FILE);
|
||||
|
||||
rotate_last_logs(KEEP_LOG_COUNT);
|
||||
get_args(&argc, &argv);
|
||||
|
||||
@@ -966,7 +1008,6 @@ main(int argc, char **argv) {
|
||||
const char *update_package = NULL;
|
||||
int wipe_data = 0, wipe_cache = 0, show_text = 0;
|
||||
bool just_exit = false;
|
||||
bool perform_backup = false;
|
||||
bool shutdown_after = false;
|
||||
|
||||
int arg;
|
||||
@@ -1027,7 +1068,7 @@ main(int argc, char **argv) {
|
||||
ui->Print("Warning: No file_contexts\n");
|
||||
}
|
||||
|
||||
//device->StartRecovery();
|
||||
device->StartRecovery();
|
||||
|
||||
printf("Command:");
|
||||
for (arg = 0; arg < argc; arg++) {
|
||||
@@ -1055,52 +1096,15 @@ main(int argc, char **argv) {
|
||||
property_get("ro.build.display.id", recovery_version, "");
|
||||
printf("\n");
|
||||
|
||||
// Check for and run startup script if script exists
|
||||
TWFunc::check_and_run_script("/sbin/runatboot.sh", "boot");
|
||||
TWFunc::check_and_run_script("/sbin/postrecoveryboot.sh", "boot");
|
||||
|
||||
#ifdef TW_INCLUDE_INJECTTWRP
|
||||
// Back up TWRP Ramdisk if needed:
|
||||
TWPartition* Boot = PartitionManager.Find_Partition_By_Path("/boot");
|
||||
LOGI("Backing up TWRP ramdisk...\n");
|
||||
if (Boot == NULL || Boot->Current_File_System != "emmc")
|
||||
TWFunc::Exec_Cmd("injecttwrp --backup /tmp/backup_recovery_ramdisk.img");
|
||||
else {
|
||||
string injectcmd = "injecttwrp --backup /tmp/backup_recovery_ramdisk.img bd=" + Boot->Actual_Block_Device;
|
||||
TWFunc::Exec_Cmd(injectcmd);
|
||||
}
|
||||
LOGI("Backup of TWRP ramdisk done.\n");
|
||||
#endif
|
||||
|
||||
int status = INSTALL_SUCCESS;
|
||||
string ORSCommand;
|
||||
|
||||
if (perform_backup) {
|
||||
char empt[50];
|
||||
gui_console_only();
|
||||
strcpy(empt, "(Current Date)");
|
||||
DataManager_SetStrValue(TW_BACKUP_NAME, empt);
|
||||
if (!OpenRecoveryScript::Insert_ORS_Command("backup BSDCAE\n"))
|
||||
status = INSTALL_ERROR;
|
||||
}
|
||||
if (status == INSTALL_SUCCESS) { // Prevent other actions if backup failed
|
||||
if (update_package != NULL) {
|
||||
ORSCommand = "install ";
|
||||
ORSCommand += update_package;
|
||||
ORSCommand += "\n";
|
||||
|
||||
if (OpenRecoveryScript::Insert_ORS_Command(ORSCommand))
|
||||
status = INSTALL_SUCCESS;
|
||||
else
|
||||
status = INSTALL_ERROR;
|
||||
/*
|
||||
status = install_package(update_package, &wipe_cache, TEMPORARY_INSTALL_FILE, true);
|
||||
if (status == INSTALL_SUCCESS && wipe_cache) {
|
||||
if (erase_volume("/cache")) {
|
||||
LOGE("Cache wipe (requested by package) failed.");
|
||||
}
|
||||
}
|
||||
|
||||
if (status != INSTALL_SUCCESS) {
|
||||
ui->Print("Installation aborted.\n");
|
||||
|
||||
@@ -1114,66 +1118,18 @@ main(int argc, char **argv) {
|
||||
}
|
||||
}
|
||||
} else if (wipe_data) {
|
||||
if (!OpenRecoveryScript::Insert_ORS_Command("wipe data\n"))
|
||||
status = INSTALL_ERROR;
|
||||
/*
|
||||
if (device->WipeData()) status = INSTALL_ERROR;
|
||||
if (erase_volume("/data")) status = INSTALL_ERROR;
|
||||
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
|
||||
if (erase_persistent_partition() == -1 ) status = INSTALL_ERROR;
|
||||
*/
|
||||
if (status != INSTALL_SUCCESS) ui->Print("Data wipe failed.\n");
|
||||
} else if (wipe_cache) {
|
||||
if (!OpenRecoveryScript::Insert_ORS_Command("wipe cache\n"))
|
||||
status = INSTALL_ERROR;
|
||||
if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
|
||||
if (status != INSTALL_SUCCESS) ui->Print("Cache wipe failed.\n");
|
||||
} else if (!just_exit) {
|
||||
status = INSTALL_NONE; // No command specified
|
||||
ui->SetBackground(RecoveryUI::NO_COMMAND);
|
||||
}
|
||||
}
|
||||
|
||||
finish_recovery(NULL);
|
||||
// Offer to decrypt if the device is encrypted
|
||||
if (DataManager_GetIntValue(TW_IS_ENCRYPTED) != 0) {
|
||||
LOGI("Is encrypted, do decrypt page first\n");
|
||||
if (gui_startPage("decrypt") != 0) {
|
||||
LOGE("Failed to start decrypt GUI page.\n");
|
||||
}
|
||||
}
|
||||
|
||||
// Read the settings file
|
||||
DataManager_ReadSettingsFile();
|
||||
// Run any outstanding OpenRecoveryScript
|
||||
if (DataManager_GetIntValue(TW_IS_ENCRYPTED) == 0 && (TWFunc::Path_Exists(SCRIPT_FILE_TMP) || TWFunc::Path_Exists(SCRIPT_FILE_CACHE))) {
|
||||
OpenRecoveryScript::Run_OpenRecoveryScript();
|
||||
}
|
||||
// Launch the main GUI
|
||||
gui_start();
|
||||
|
||||
// Check for su to see if the device is rooted or not
|
||||
if (PartitionManager.Mount_By_Path("/system", false)) {
|
||||
// Disable flashing of stock recovery
|
||||
if (TWFunc::Path_Exists("/system/recovery-from-boot.p") && TWFunc::Path_Exists("/system/etc/install-recovery.sh")) {
|
||||
rename("/system/recovery-from-boot.p", "/system/recovery-from-boot.bak");
|
||||
ui_print("Renamed stock recovery file in /system to prevent\nthe stock ROM from replacing TWRP.\n");
|
||||
}
|
||||
if (TWFunc::Path_Exists("/supersu/su") && !TWFunc::Path_Exists("/system/bin/su") && !TWFunc::Path_Exists("/system/xbin/su") && !TWFunc::Path_Exists("/system/bin/.ext/.su")) {
|
||||
// Device doesn't have su installed
|
||||
DataManager_SetIntValue("tw_busy", 1);
|
||||
if (gui_startPage("installsu") != 0) {
|
||||
LOGE("Failed to start decrypt GUI page.\n");
|
||||
}
|
||||
} else if (TWFunc::Check_su_Perms() > 0) {
|
||||
// su perms are set incorrectly
|
||||
DataManager_SetIntValue("tw_busy", 1);
|
||||
if (gui_startPage("fixsu") != 0) {
|
||||
LOGE("Failed to start decrypt GUI page.\n");
|
||||
}
|
||||
}
|
||||
sync();
|
||||
PartitionManager.UnMount_By_Path("/system", false);
|
||||
}
|
||||
|
||||
if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) {
|
||||
copy_logs();
|
||||
@@ -1187,27 +1143,6 @@ main(int argc, char **argv) {
|
||||
|
||||
// Save logs and clean up before rebooting or shutting down.
|
||||
finish_recovery(send_intent);
|
||||
ui->Print("Rebooting...\n");
|
||||
char backup_arg_char[50];
|
||||
strcpy(backup_arg_char, DataManager_GetStrValue("tw_reboot_arg"));
|
||||
string backup_arg = backup_arg_char;
|
||||
if (backup_arg == "recovery")
|
||||
TWFunc::tw_reboot(rb_recovery);
|
||||
else if (backup_arg == "poweroff")
|
||||
TWFunc::tw_reboot(rb_poweroff);
|
||||
else if (backup_arg == "bootloader")
|
||||
TWFunc::tw_reboot(rb_bootloader);
|
||||
else if (backup_arg == "download")
|
||||
TWFunc::tw_reboot(rb_download);
|
||||
else
|
||||
TWFunc::tw_reboot(rb_system);
|
||||
|
||||
#ifdef ANDROID_RB_RESTART
|
||||
android_reboot(ANDROID_RB_RESTART, 0, 0);
|
||||
#else
|
||||
reboot(RB_AUTOBOOT);
|
||||
#endif
|
||||
property_set(ANDROID_RB_PROPERTY, "reboot,");
|
||||
|
||||
switch (after) {
|
||||
case Device::SHUTDOWN:
|
||||
|
||||
+18
-5
@@ -164,7 +164,12 @@ char* parse_recovery_command_file()
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FILE* fo = fopen(RECOVERY_COMMAND_FILE_TMP, "w");
|
||||
int fd = open(RECOVERY_COMMAND_FILE_TMP, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0) {
|
||||
ALOGE("failed to open %s\n", RECOVERY_COMMAND_FILE_TMP);
|
||||
return NULL;
|
||||
}
|
||||
FILE* fo = fdopen(fd, "w");
|
||||
|
||||
while (fgets(temp, sizeof(temp), f)) {
|
||||
printf("read: %s", temp);
|
||||
@@ -175,6 +180,7 @@ char* parse_recovery_command_file()
|
||||
fputs(temp, fo);
|
||||
}
|
||||
fclose(f);
|
||||
fsync(fd);
|
||||
fclose(fo);
|
||||
|
||||
if (fn) {
|
||||
@@ -190,7 +196,12 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
||||
struct stat sb;
|
||||
int ret;
|
||||
|
||||
FILE* mapf = fopen(map_file, "w");
|
||||
int mapfd = open(map_file, O_WRONLY | O_CREAT | O_SYNC, S_IRUSR | S_IWUSR);
|
||||
if (mapfd < 0) {
|
||||
ALOGE("failed to open %s\n", map_file);
|
||||
return -1;
|
||||
}
|
||||
FILE* mapf = fdopen(mapfd, "w");
|
||||
|
||||
ret = stat(path, &sb);
|
||||
if (ret != 0) {
|
||||
@@ -232,7 +243,7 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
||||
|
||||
int wfd = -1;
|
||||
if (encrypted) {
|
||||
wfd = open(blk_dev, O_WRONLY);
|
||||
wfd = open(blk_dev, O_WRONLY | O_SYNC);
|
||||
if (wfd < 0) {
|
||||
ALOGE("failed to open fd for writing: %s\n", strerror(errno));
|
||||
return -1;
|
||||
@@ -302,9 +313,11 @@ int produce_block_map(const char* path, const char* map_file, const char* blk_de
|
||||
fprintf(mapf, "%d %d\n", ranges[i*2], ranges[i*2+1]);
|
||||
}
|
||||
|
||||
fsync(mapfd);
|
||||
fclose(mapf);
|
||||
close(fd);
|
||||
if (encrypted) {
|
||||
fsync(wfd);
|
||||
close(wfd);
|
||||
}
|
||||
|
||||
@@ -318,7 +331,7 @@ void wipe_misc() {
|
||||
struct fstab_rec* v = &fstab->recs[i];
|
||||
if (!v->mount_point) continue;
|
||||
if (strcmp(v->mount_point, "/misc") == 0) {
|
||||
int fd = open(v->blk_device, O_WRONLY);
|
||||
int fd = open(v->blk_device, O_WRONLY | O_SYNC);
|
||||
uint8_t zeroes[1088]; // sizeof(bootloader_message) from recovery
|
||||
memset(zeroes, 0, sizeof(zeroes));
|
||||
|
||||
@@ -333,7 +346,7 @@ void wipe_misc() {
|
||||
written += w;
|
||||
}
|
||||
}
|
||||
|
||||
fsync(fd);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,16 @@ LOCAL_STATIC_LIBRARIES += libflashutils libmmcutils libbmlutils
|
||||
LOCAL_STATIC_LIBRARIES += libmincrypttwrp libbz
|
||||
LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
|
||||
LOCAL_STATIC_LIBRARIES += libselinux
|
||||
tune2fs_static_libraries := \
|
||||
libext2_com_err \
|
||||
libext2_blkid \
|
||||
libext2_quota \
|
||||
libext2_uuid_static \
|
||||
libext2_e2p \
|
||||
libext2fs
|
||||
LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries)
|
||||
|
||||
LOCAL_C_INCLUDES += external/e2fsprogs/misc
|
||||
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
|
||||
|
||||
# Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function
|
||||
|
||||
+210
-46
@@ -61,7 +61,7 @@ static RangeSet* parse_range(char* text) {
|
||||
|
||||
RangeSet* out = malloc(sizeof(RangeSet) + num * sizeof(int));
|
||||
if (out == NULL) {
|
||||
fprintf(stderr, "failed to allocate range of %lu bytes\n",
|
||||
fprintf(stderr, "failed to allocate range of %zu bytes\n",
|
||||
sizeof(RangeSet) + num * sizeof(int));
|
||||
exit(1);
|
||||
}
|
||||
@@ -245,6 +245,133 @@ static void* unzip_new_data(void* cookie) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Do a source/target load for move/bsdiff/imgdiff in version 1.
|
||||
// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
|
||||
// to parse the remainder of the string as:
|
||||
//
|
||||
// <src_range> <tgt_range>
|
||||
//
|
||||
// The source range is loaded into the provided buffer, reallocating
|
||||
// it to make it larger if necessary. The target ranges are returned
|
||||
// in *tgt, if tgt is non-NULL.
|
||||
|
||||
static void LoadSrcTgtVersion1(char* wordsave, RangeSet** tgt, int* src_blocks,
|
||||
uint8_t** buffer, size_t* buffer_alloc, int fd) {
|
||||
char* word;
|
||||
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
RangeSet* src = parse_range(word);
|
||||
|
||||
if (tgt != NULL) {
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
*tgt = parse_range(word);
|
||||
}
|
||||
|
||||
allocate(src->size * BLOCKSIZE, buffer, buffer_alloc);
|
||||
size_t p = 0;
|
||||
int i;
|
||||
for (i = 0; i < src->count; ++i) {
|
||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||
readblock(fd, *buffer+p, sz);
|
||||
p += sz;
|
||||
}
|
||||
|
||||
*src_blocks = src->size;
|
||||
free(src);
|
||||
}
|
||||
|
||||
static void MoveRange(uint8_t* dest, RangeSet* locs, const uint8_t* source) {
|
||||
// source contains packed data, which we want to move to the
|
||||
// locations given in *locs in the dest buffer. source and dest
|
||||
// may be the same buffer.
|
||||
|
||||
int start = locs->size;
|
||||
int i;
|
||||
for (i = locs->count-1; i >= 0; --i) {
|
||||
int blocks = locs->pos[i*2+1] - locs->pos[i*2];
|
||||
start -= blocks;
|
||||
memmove(dest + (locs->pos[i*2] * BLOCKSIZE), source + (start * BLOCKSIZE),
|
||||
blocks * BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// Do a source/target load for move/bsdiff/imgdiff in version 2.
|
||||
// 'wordsave' is the save_ptr of a strtok_r()-in-progress. We expect
|
||||
// to parse the remainder of the string as one of:
|
||||
//
|
||||
// <tgt_range> <src_block_count> <src_range>
|
||||
// (loads data from source image only)
|
||||
//
|
||||
// <tgt_range> <src_block_count> - <[stash_id:stash_range] ...>
|
||||
// (loads data from stashes only)
|
||||
//
|
||||
// <tgt_range> <src_block_count> <src_range> <src_loc> <[stash_id:stash_range] ...>
|
||||
// (loads data from both source image and stashes)
|
||||
//
|
||||
// On return, buffer is filled with the loaded source data (rearranged
|
||||
// and combined with stashed data as necessary). buffer may be
|
||||
// reallocated if needed to accommodate the source data. *tgt is the
|
||||
// target RangeSet. Any stashes required are taken from stash_table
|
||||
// and free()'d after being used.
|
||||
|
||||
static void LoadSrcTgtVersion2(char* wordsave, RangeSet** tgt, int* src_blocks,
|
||||
uint8_t** buffer, size_t* buffer_alloc, int fd,
|
||||
uint8_t** stash_table) {
|
||||
char* word;
|
||||
|
||||
if (tgt != NULL) {
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
*tgt = parse_range(word);
|
||||
}
|
||||
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
*src_blocks = strtol(word, NULL, 0);
|
||||
|
||||
allocate(*src_blocks * BLOCKSIZE, buffer, buffer_alloc);
|
||||
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
if (word[0] == '-' && word[1] == '\0') {
|
||||
// no source ranges, only stashes
|
||||
} else {
|
||||
RangeSet* src = parse_range(word);
|
||||
|
||||
size_t p = 0;
|
||||
int i;
|
||||
for (i = 0; i < src->count; ++i) {
|
||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||
readblock(fd, *buffer+p, sz);
|
||||
p += sz;
|
||||
}
|
||||
free(src);
|
||||
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
if (word == NULL) {
|
||||
// no stashes, only source range
|
||||
return;
|
||||
}
|
||||
|
||||
RangeSet* locs = parse_range(word);
|
||||
MoveRange(*buffer, locs, *buffer);
|
||||
}
|
||||
|
||||
while ((word = strtok_r(NULL, " ", &wordsave)) != NULL) {
|
||||
// Each word is a an index into the stash table, a colon, and
|
||||
// then a rangeset describing where in the source block that
|
||||
// stashed data should go.
|
||||
char* colonsave = NULL;
|
||||
char* colon = strtok_r(word, ":", &colonsave);
|
||||
int stash_id = strtol(colon, NULL, 0);
|
||||
colon = strtok_r(NULL, ":", &colonsave);
|
||||
RangeSet* locs = parse_range(colon);
|
||||
MoveRange(*buffer, locs, stash_table[stash_id]);
|
||||
free(stash_table[stash_id]);
|
||||
stash_table[stash_id] = NULL;
|
||||
free(locs);
|
||||
}
|
||||
}
|
||||
|
||||
// args:
|
||||
// - block device (or file) to modify in-place
|
||||
// - transfer list (blob)
|
||||
@@ -311,23 +438,33 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
// new [rangeset]
|
||||
// - fill the blocks with data read from the new_data file
|
||||
//
|
||||
// bsdiff patchstart patchlen [src rangeset] [tgt rangeset]
|
||||
// imgdiff patchstart patchlen [src rangeset] [tgt rangeset]
|
||||
// - read the source blocks, apply a patch, write result to
|
||||
// target blocks. bsdiff or imgdiff specifies the type of
|
||||
// patch.
|
||||
//
|
||||
// move [src rangeset] [tgt rangeset]
|
||||
// - copy data from source blocks to target blocks (no patch
|
||||
// needed; rangesets are the same size)
|
||||
//
|
||||
// erase [rangeset]
|
||||
// - mark the given blocks as empty
|
||||
//
|
||||
// move <...>
|
||||
// bsdiff <patchstart> <patchlen> <...>
|
||||
// imgdiff <patchstart> <patchlen> <...>
|
||||
// - read the source blocks, apply a patch (or not in the
|
||||
// case of move), write result to target blocks. bsdiff or
|
||||
// imgdiff specifies the type of patch; move means no patch
|
||||
// at all.
|
||||
//
|
||||
// The format of <...> differs between versions 1 and 2;
|
||||
// see the LoadSrcTgtVersion{1,2}() functions for a
|
||||
// description of what's expected.
|
||||
//
|
||||
// stash <stash_id> <src_range>
|
||||
// - (version 2 only) load the given source range and stash
|
||||
// the data in the given slot of the stash table.
|
||||
//
|
||||
// The creator of the transfer list will guarantee that no block
|
||||
// is read (ie, used as the source for a patch or move) after it
|
||||
// has been written.
|
||||
//
|
||||
// In version 2, the creator will guarantee that a given stash is
|
||||
// loaded (with a stash command) before it's used in a
|
||||
// move/bsdiff/imgdiff command.
|
||||
//
|
||||
// Within one command the source and target ranges may overlap so
|
||||
// in general we need to read the entire source into memory before
|
||||
// writing anything to the target blocks.
|
||||
@@ -379,12 +516,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
|
||||
line = strtok_r(transfer_list, "\n", &linesave);
|
||||
|
||||
int version;
|
||||
// first line in transfer list is the version number; currently
|
||||
// there's only version 1.
|
||||
if (strcmp(line, "1") != 0) {
|
||||
if (strcmp(line, "1") == 0) {
|
||||
version = 1;
|
||||
} else if (strcmp(line, "2") == 0) {
|
||||
version = 2;
|
||||
} else {
|
||||
ErrorAbort(state, "unexpected transfer list version [%s]\n", line);
|
||||
goto done;
|
||||
}
|
||||
printf("blockimg version is %d\n", version);
|
||||
|
||||
// second line in transfer list is the total number of blocks we
|
||||
// expect to write.
|
||||
@@ -394,33 +537,49 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
if (total_blocks == 0) ++total_blocks;
|
||||
int blocks_so_far = 0;
|
||||
|
||||
uint8_t** stash_table = NULL;
|
||||
if (version >= 2) {
|
||||
// Next line is how many stash entries are needed simultaneously.
|
||||
line = strtok_r(NULL, "\n", &linesave);
|
||||
int stash_entries = strtol(line, NULL, 0);
|
||||
|
||||
stash_table = (uint8_t**) calloc(stash_entries, sizeof(uint8_t*));
|
||||
if (stash_table == NULL) {
|
||||
fprintf(stderr, "failed to allocate %d-entry stash table\n", stash_entries);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Next line is the maximum number of blocks that will be
|
||||
// stashed simultaneously. This could be used to verify that
|
||||
// enough memory or scratch disk space is available.
|
||||
line = strtok_r(NULL, "\n", &linesave);
|
||||
int stash_max_blocks = strtol(line, NULL, 0);
|
||||
}
|
||||
|
||||
uint8_t* buffer = NULL;
|
||||
size_t buffer_alloc = 0;
|
||||
|
||||
// third and subsequent lines are all individual transfer commands.
|
||||
for (line = strtok_r(NULL, "\n", &linesave); line;
|
||||
line = strtok_r(NULL, "\n", &linesave)) {
|
||||
|
||||
char* style;
|
||||
style = strtok_r(line, " ", &wordsave);
|
||||
|
||||
if (strcmp("move", style) == 0) {
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
RangeSet* src = parse_range(word);
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
RangeSet* tgt = parse_range(word);
|
||||
|
||||
printf(" moving %d blocks\n", src->size);
|
||||
|
||||
allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
|
||||
size_t p = 0;
|
||||
for (i = 0; i < src->count; ++i) {
|
||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||
readblock(fd, buffer+p, sz);
|
||||
p += sz;
|
||||
RangeSet* tgt;
|
||||
int src_blocks;
|
||||
if (version == 1) {
|
||||
LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
|
||||
&buffer, &buffer_alloc, fd);
|
||||
} else if (version == 2) {
|
||||
LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
|
||||
&buffer, &buffer_alloc, fd, stash_table);
|
||||
}
|
||||
|
||||
p = 0;
|
||||
printf(" moving %d blocks\n", src_blocks);
|
||||
|
||||
size_t p = 0;
|
||||
for (i = 0; i < tgt->count; ++i) {
|
||||
check_lseek(fd, (off64_t)tgt->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||
size_t sz = (tgt->pos[i*2+1] - tgt->pos[i*2]) * BLOCKSIZE;
|
||||
@@ -432,9 +591,20 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
||||
fflush(cmd_pipe);
|
||||
|
||||
free(src);
|
||||
free(tgt);
|
||||
|
||||
} else if (strcmp("stash", style) == 0) {
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
int stash_id = strtol(word, NULL, 0);
|
||||
int src_blocks;
|
||||
size_t stash_alloc = 0;
|
||||
|
||||
// Even though the "stash" style only appears in version
|
||||
// 2, the version 1 source loader happens to do exactly
|
||||
// what we want to read data into the stash_table.
|
||||
LoadSrcTgtVersion1(wordsave, NULL, &src_blocks,
|
||||
stash_table + stash_id, &stash_alloc, fd);
|
||||
|
||||
} else if (strcmp("zero", style) == 0 ||
|
||||
(DEBUG_ERASE && strcmp("erase", style) == 0)) {
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
@@ -493,23 +663,18 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
size_t patch_len = strtoul(word, NULL, 0);
|
||||
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
RangeSet* src = parse_range(word);
|
||||
word = strtok_r(NULL, " ", &wordsave);
|
||||
RangeSet* tgt = parse_range(word);
|
||||
|
||||
printf(" patching %d blocks to %d\n", src->size, tgt->size);
|
||||
|
||||
// Read the source into memory.
|
||||
allocate(src->size * BLOCKSIZE, &buffer, &buffer_alloc);
|
||||
size_t p = 0;
|
||||
for (i = 0; i < src->count; ++i) {
|
||||
check_lseek(fd, (off64_t)src->pos[i*2] * BLOCKSIZE, SEEK_SET);
|
||||
size_t sz = (src->pos[i*2+1] - src->pos[i*2]) * BLOCKSIZE;
|
||||
readblock(fd, buffer+p, sz);
|
||||
p += sz;
|
||||
RangeSet* tgt;
|
||||
int src_blocks;
|
||||
if (version == 1) {
|
||||
LoadSrcTgtVersion1(wordsave, &tgt, &src_blocks,
|
||||
&buffer, &buffer_alloc, fd);
|
||||
} else if (version == 2) {
|
||||
LoadSrcTgtVersion2(wordsave, &tgt, &src_blocks,
|
||||
&buffer, &buffer_alloc, fd, stash_table);
|
||||
}
|
||||
|
||||
printf(" patching %d blocks to %d\n", src_blocks, tgt->size);
|
||||
|
||||
Value patch_value;
|
||||
patch_value.type = VAL_BLOB;
|
||||
patch_value.size = patch_len;
|
||||
@@ -523,11 +688,11 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
check_lseek(fd, (off64_t)tgt->pos[0] * BLOCKSIZE, SEEK_SET);
|
||||
|
||||
if (style[0] == 'i') { // imgdiff
|
||||
ApplyImagePatch(buffer, src->size * BLOCKSIZE,
|
||||
ApplyImagePatch(buffer, src_blocks * BLOCKSIZE,
|
||||
&patch_value,
|
||||
&RangeSinkWrite, &rss, NULL, NULL);
|
||||
} else {
|
||||
ApplyBSDiffPatch(buffer, src->size * BLOCKSIZE,
|
||||
ApplyBSDiffPatch(buffer, src_blocks * BLOCKSIZE,
|
||||
&patch_value, 0,
|
||||
&RangeSinkWrite, &rss, NULL);
|
||||
}
|
||||
@@ -541,7 +706,6 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]
|
||||
fprintf(cmd_pipe, "set_progress %.4f\n", (double)blocks_so_far / total_blocks);
|
||||
fflush(cmd_pipe);
|
||||
|
||||
free(src);
|
||||
free(tgt);
|
||||
} else if (!DEBUG_ERASE && strcmp("erase", style) == 0) {
|
||||
struct stat st;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "applypatch/applypatch.h"
|
||||
#include "flashutils/flashutils.h"
|
||||
#include "install.h"
|
||||
#include "tune2fs.h"
|
||||
|
||||
#ifdef USE_EXT4
|
||||
#include "make_ext4fs.h"
|
||||
@@ -1489,6 +1490,37 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) {
|
||||
if (argc == 0) {
|
||||
return ErrorAbort(state, "%s() expects args, got %d", name, argc);
|
||||
}
|
||||
|
||||
char** args = ReadVarArgs(state, argc, argv);
|
||||
if (args == NULL) {
|
||||
return ErrorAbort(state, "%s() could not read args", name);
|
||||
}
|
||||
|
||||
int i;
|
||||
char** args2 = malloc(sizeof(char*) * (argc+1));
|
||||
// Tune2fs expects the program name as its args[0]
|
||||
args2[0] = strdup(name);
|
||||
for (i = 0; i < argc; ++i) {
|
||||
args2[i + 1] = args[i];
|
||||
}
|
||||
int result = tune2fs_main(argc + 1, args2);
|
||||
for (i = 0; i < argc; ++i) {
|
||||
free(args[i]);
|
||||
}
|
||||
free(args);
|
||||
|
||||
free(args2[0]);
|
||||
free(args2);
|
||||
if (result != 0) {
|
||||
return ErrorAbort(state, "%s() returned error code %d", name, result);
|
||||
}
|
||||
return StringValue(strdup("t"));
|
||||
}
|
||||
|
||||
void RegisterInstallFunctions() {
|
||||
RegisterFunction("mount", MountFn);
|
||||
RegisterFunction("is_mounted", IsMountedFn);
|
||||
@@ -1539,4 +1571,5 @@ void RegisterInstallFunctions() {
|
||||
RegisterFunction("set_stage", SetStageFn);
|
||||
|
||||
RegisterFunction("enable_reboot", EnableRebootFn);
|
||||
RegisterFunction("tune2fs", Tune2FsFn);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user