summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk9
-rw-r--r--applypatch/applypatch.c277
-rw-r--r--common.h10
-rw-r--r--default_recovery_ui.c2
-rw-r--r--install.c2
-rw-r--r--recovery.c183
-rw-r--r--roots.c36
-rw-r--r--ui.c8
-rw-r--r--updater/Android.mk8
-rw-r--r--updater/install.c81
10 files changed, 442 insertions, 174 deletions
diff --git a/Android.mk b/Android.mk
index b0fefbd90..4a3d28577 100644
--- a/Android.mk
+++ b/Android.mk
@@ -24,6 +24,14 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true
RECOVERY_API_VERSION := 3
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
+LOCAL_STATIC_LIBRARIES :=
+
+ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
+LOCAL_CFLAGS += -DUSE_EXT4
+LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_STATIC_LIBRARIES += libext4_utils libz
+endif
+
# This binary is in the recovery ramdisk, which is otherwise a copy of root.
# It gets copied there in config/Makefile. LOCAL_MODULE_TAGS suppresses
# a (redundant) copy of the binary in /system/bin for user builds.
@@ -31,7 +39,6 @@ LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
LOCAL_MODULE_TAGS := eng
-LOCAL_STATIC_LIBRARIES :=
ifeq ($(TARGET_RECOVERY_UI_LIB),)
LOCAL_SRC_FILES += default_recovery_ui.c
else
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index 99d366165..d18282117 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -30,10 +30,10 @@
#include "mtdutils/mtdutils.h"
#include "edify/expr.h"
-int SaveFileContents(const char* filename, FileContents file);
-int LoadMTDContents(const char* filename, FileContents* file);
+static int SaveFileContents(const char* filename, FileContents file);
+static int LoadPartitionContents(const char* filename, FileContents* file);
int ParseSha1(const char* str, uint8_t* digest);
-ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
+static ssize_t FileSink(unsigned char* data, ssize_t len, void* token);
static int mtd_partitions_scanned = 0;
@@ -42,10 +42,11 @@ static int mtd_partitions_scanned = 0;
int LoadFileContents(const char* filename, FileContents* file) {
file->data = NULL;
- // A special 'filename' beginning with "MTD:" means to load the
- // contents of an MTD partition.
- if (strncmp(filename, "MTD:", 4) == 0) {
- return LoadMTDContents(filename, file);
+ // A special 'filename' beginning with "MTD:" or "EMMC:" means to
+ // load the contents of a partition.
+ if (strncmp(filename, "MTD:", 4) == 0 ||
+ strncmp(filename, "EMMC:", 5) == 0) {
+ return LoadPartitionContents(filename, file);
}
if (stat(filename, &file->st) != 0) {
@@ -98,26 +99,35 @@ void FreeFileContents(FileContents* file) {
free(file);
}
-// Load the contents of an MTD partition into the provided
+// Load the contents of an MTD or EMMC partition into the provided
// FileContents. filename should be a string of the form
-// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:...".
-// The smallest size_n bytes for which that prefix of the mtd contents
-// has the corresponding sha1 hash will be loaded. It is acceptable
-// for a size value to be repeated with different sha1s. Will return
-// 0 on success.
+// "MTD:<partition_name>:<size_1>:<sha1_1>:<size_2>:<sha1_2>:..." (or
+// "EMMC:<partition_device>:..."). The smallest size_n bytes for
+// which that prefix of the partition contents has the corresponding
+// sha1 hash will be loaded. It is acceptable for a size value to be
+// repeated with different sha1s. Will return 0 on success.
//
// This complexity is needed because if an OTA installation is
// interrupted, the partition might contain either the source or the
// target data, which might be of different lengths. We need to know
-// the length in order to read from MTD (there is no "end-of-file"
-// marker), so the caller must specify the possible lengths and the
-// hash of the data, and we'll do the load expecting to find one of
-// those hashes.
-int LoadMTDContents(const char* filename, FileContents* file) {
+// the length in order to read from a partition (there is no
+// "end-of-file" marker), so the caller must specify the possible
+// lengths and the hash of the data, and we'll do the load expecting
+// to find one of those hashes.
+enum PartitionType { MTD, EMMC };
+
+static int LoadPartitionContents(const char* filename, FileContents* file) {
char* copy = strdup(filename);
const char* magic = strtok(copy, ":");
- if (strcmp(magic, "MTD") != 0) {
- printf("LoadMTDContents called with bad filename (%s)\n",
+
+ enum PartitionType type;
+
+ if (strcmp(magic, "MTD") == 0) {
+ type = MTD;
+ } else if (strcmp(magic, "EMMC") == 0) {
+ type = EMMC;
+ } else {
+ printf("LoadPartitionContents called with bad filename (%s)\n",
filename);
return -1;
}
@@ -131,7 +141,7 @@ int LoadMTDContents(const char* filename, FileContents* file) {
}
}
if (colons < 3 || colons%2 == 0) {
- printf("LoadMTDContents called with bad filename (%s)\n",
+ printf("LoadPartitionContents called with bad filename (%s)\n",
filename);
}
@@ -144,7 +154,7 @@ int LoadMTDContents(const char* filename, FileContents* file) {
const char* size_str = strtok(NULL, ":");
size[i] = strtol(size_str, NULL, 10);
if (size[i] == 0) {
- printf("LoadMTDContents called with bad size (%s)\n", filename);
+ printf("LoadPartitionContents called with bad size (%s)\n", filename);
return -1;
}
sha1sum[i] = strtok(NULL, ":");
@@ -156,23 +166,38 @@ int LoadMTDContents(const char* filename, FileContents* file) {
size_array = size;
qsort(index, pairs, sizeof(int), compare_size_indices);
- if (!mtd_partitions_scanned) {
- mtd_scan_partitions();
- mtd_partitions_scanned = 1;
- }
+ MtdReadContext* ctx = NULL;
+ FILE* dev = NULL;
- const MtdPartition* mtd = mtd_find_partition_by_name(partition);
- if (mtd == NULL) {
- printf("mtd partition \"%s\" not found (loading %s)\n",
- partition, filename);
- return -1;
- }
+ switch (type) {
+ case MTD:
+ if (!mtd_partitions_scanned) {
+ mtd_scan_partitions();
+ mtd_partitions_scanned = 1;
+ }
- MtdReadContext* ctx = mtd_read_partition(mtd);
- if (ctx == NULL) {
- printf("failed to initialize read of mtd partition \"%s\"\n",
- partition);
- return -1;
+ const MtdPartition* mtd = mtd_find_partition_by_name(partition);
+ if (mtd == NULL) {
+ printf("mtd partition \"%s\" not found (loading %s)\n",
+ partition, filename);
+ return -1;
+ }
+
+ ctx = mtd_read_partition(mtd);
+ if (ctx == NULL) {
+ printf("failed to initialize read of mtd partition \"%s\"\n",
+ partition);
+ return -1;
+ }
+ break;
+
+ case EMMC:
+ dev = fopen(partition, "rb");
+ if (dev == NULL) {
+ printf("failed to open emmc partition \"%s\": %s\n",
+ partition, strerror(errno));
+ return -1;
+ }
}
SHA_CTX sha_ctx;
@@ -191,7 +216,15 @@ int LoadMTDContents(const char* filename, FileContents* file) {
size_t next = size[index[i]] - file->size;
size_t read = 0;
if (next > 0) {
- read = mtd_read_data(ctx, p, next);
+ switch (type) {
+ case MTD:
+ read = mtd_read_data(ctx, p, next);
+ break;
+
+ case EMMC:
+ read = fread(p, 1, next, dev);
+ break;
+ }
if (next != read) {
printf("short read (%d bytes of %d) for partition \"%s\"\n",
read, next, partition);
@@ -220,7 +253,7 @@ int LoadMTDContents(const char* filename, FileContents* file) {
if (memcmp(sha_so_far, parsed_sha, SHA_DIGEST_SIZE) == 0) {
// we have a match. stop reading the partition; we'll return
// the data we've read so far.
- printf("mtd read matched size %d sha %s\n",
+ printf("partition read matched size %d sha %s\n",
size[index[i]], sha1sum[index[i]]);
break;
}
@@ -228,12 +261,21 @@ int LoadMTDContents(const char* filename, FileContents* file) {
p += read;
}
- mtd_read_close(ctx);
+ switch (type) {
+ case MTD:
+ mtd_read_close(ctx);
+ break;
+
+ case EMMC:
+ fclose(dev);
+ break;
+ }
+
if (i == pairs) {
// Ran off the end of the list of (size,sha1) pairs without
// finding a match.
- printf("contents of MTD partition \"%s\" didn't match %s\n",
+ printf("contents of partition \"%s\" didn't match %s\n",
partition, filename);
free(file->data);
file->data = NULL;
@@ -261,7 +303,7 @@ int LoadMTDContents(const char* filename, FileContents* file) {
// Save the contents of the given FileContents object under the given
// filename. Return 0 on success.
-int SaveFileContents(const char* filename, FileContents file) {
+static int SaveFileContents(const char* filename, FileContents file) {
int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
if (fd < 0) {
printf("failed to open \"%s\" for write: %s\n",
@@ -292,61 +334,87 @@ int SaveFileContents(const char* filename, FileContents file) {
return 0;
}
-// Write a memory buffer to target_mtd partition, a string of the form
-// "MTD:<partition>[:...]". Return 0 on success.
-int WriteToMTDPartition(unsigned char* data, size_t len,
- const char* target_mtd) {
- char* partition = strchr(target_mtd, ':');
- if (partition == NULL) {
- printf("bad MTD target name \"%s\"\n", target_mtd);
- return -1;
- }
- ++partition;
- // Trim off anything after a colon, eg "MTD:boot:blah:blah:blah...".
- // We want just the partition name "boot".
- partition = strdup(partition);
- char* end = strchr(partition, ':');
- if (end != NULL)
- *end = '\0';
-
- if (!mtd_partitions_scanned) {
- mtd_scan_partitions();
- mtd_partitions_scanned = 1;
- }
+// Write a memory buffer to 'target' partition, a string of the form
+// "MTD:<partition>[:...]" or "EMMC:<partition_device>:". Return 0 on
+// success.
+int WriteToPartition(unsigned char* data, size_t len,
+ const char* target) {
+ char* copy = strdup(target);
+ const char* magic = strtok(copy, ":");
- const MtdPartition* mtd = mtd_find_partition_by_name(partition);
- if (mtd == NULL) {
- printf("mtd partition \"%s\" not found for writing\n", partition);
+ enum PartitionType type;
+ if (strcmp(magic, "MTD") == 0) {
+ type = MTD;
+ } else if (strcmp(magic, "EMMC") == 0) {
+ type = EMMC;
+ } else {
+ printf("WriteToPartition called with bad target (%s)\n", target);
return -1;
}
+ const char* partition = strtok(NULL, ":");
- MtdWriteContext* ctx = mtd_write_partition(mtd);
- if (ctx == NULL) {
- printf("failed to init mtd partition \"%s\" for writing\n",
- partition);
+ if (partition == NULL) {
+ printf("bad partition target name \"%s\"\n", target);
return -1;
}
- size_t written = mtd_write_data(ctx, (char*)data, len);
- if (written != len) {
- printf("only wrote %d of %d bytes to MTD %s\n",
- written, len, partition);
- mtd_write_close(ctx);
- return -1;
- }
+ switch (type) {
+ case MTD:
+ if (!mtd_partitions_scanned) {
+ mtd_scan_partitions();
+ mtd_partitions_scanned = 1;
+ }
- if (mtd_erase_blocks(ctx, -1) < 0) {
- printf("error finishing mtd write of %s\n", partition);
- mtd_write_close(ctx);
- return -1;
- }
+ const MtdPartition* mtd = mtd_find_partition_by_name(partition);
+ if (mtd == NULL) {
+ printf("mtd partition \"%s\" not found for writing\n",
+ partition);
+ return -1;
+ }
- if (mtd_write_close(ctx)) {
- printf("error closing mtd write of %s\n", partition);
- return -1;
+ MtdWriteContext* ctx = mtd_write_partition(mtd);
+ if (ctx == NULL) {
+ printf("failed to init mtd partition \"%s\" for writing\n",
+ partition);
+ return -1;
+ }
+
+ size_t written = mtd_write_data(ctx, (char*)data, len);
+ if (written != len) {
+ printf("only wrote %d of %d bytes to MTD %s\n",
+ written, len, partition);
+ mtd_write_close(ctx);
+ return -1;
+ }
+
+ if (mtd_erase_blocks(ctx, -1) < 0) {
+ printf("error finishing mtd write of %s\n", partition);
+ mtd_write_close(ctx);
+ return -1;
+ }
+
+ if (mtd_write_close(ctx)) {
+ printf("error closing mtd write of %s\n", partition);
+ return -1;
+ }
+ break;
+
+ case EMMC:
+ ;
+ FILE* f = fopen(partition, "wb");
+ if (fwrite(data, 1, len, f) != len) {
+ printf("short write writing to %s (%s)\n",
+ partition, strerror(errno));
+ return -1;
+ }
+ if (fclose(f) != 0) {
+ printf("error closing %s (%s)\n", partition, strerror(errno));
+ return -1;
+ }
+ break;
}
- free(partition);
+ free(copy);
return 0;
}
@@ -406,7 +474,7 @@ int applypatch_check(const char* filename,
file.data = NULL;
// It's okay to specify no sha1s; the check will pass if the
- // LoadFileContents is successful. (Useful for reading MTD
+ // LoadFileContents is successful. (Useful for reading
// partitions, where the filename encodes the sha1s; no need to
// check them twice.)
if (LoadFileContents(filename, &file) != 0 ||
@@ -518,8 +586,8 @@ int CacheSizeCheck(size_t bytes) {
// - otherwise, or if any error is encountered, exits with non-zero
// status.
//
-// <source_filename> may refer to an MTD partition to read the source
-// data. See the comments for the LoadMTDContents() function above
+// <source_filename> may refer to a partition to read the source data.
+// See the comments for the LoadPartition Contents() function above
// for the format of such a filename.
int applypatch(const char* source_filename,
@@ -623,14 +691,16 @@ int applypatch(const char* source_filename,
// Is there enough room in the target filesystem to hold the patched
// file?
- if (strncmp(target_filename, "MTD:", 4) == 0) {
- // If the target is an MTD partition, we're actually going to
- // write the output to /tmp and then copy it to the partition.
- // statfs() always returns 0 blocks free for /tmp, so instead
- // we'll just assume that /tmp has enough space to hold the file.
+ if (strncmp(target_filename, "MTD:", 4) == 0 ||
+ strncmp(target_filename, "EMMC:", 5) == 0) {
+ // If the target is a partition, we're actually going to
+ // write the output to /tmp and then copy it to the
+ // partition. statfs() always returns 0 blocks free for
+ // /tmp, so instead we'll just assume that /tmp has enough
+ // space to hold the file.
- // We still write the original source to cache, in case the MTD
- // write is interrupted.
+ // We still write the original source to cache, in case
+ // the partition write is interrupted.
if (MakeFreeSpaceOnCache(source_file.size) < 0) {
printf("not enough free space on /cache\n");
return 1;
@@ -660,11 +730,13 @@ int applypatch(const char* source_filename,
// copy the source file to cache, then delete it from the original
// location.
- if (strncmp(source_filename, "MTD:", 4) == 0) {
+ if (strncmp(source_filename, "MTD:", 4) == 0 ||
+ strncmp(source_filename, "EMMC:", 5) == 0) {
// It's impossible to free space on the target filesystem by
- // deleting the source if the source is an MTD partition. If
+ // deleting the source if the source is a partition. If
// we're ever in a state where we need to do this, fail.
- printf("not enough free space for target but source is MTD\n");
+ printf("not enough free space for target but source "
+ "is partition\n");
return 1;
}
@@ -703,7 +775,8 @@ int applypatch(const char* source_filename,
void* token = NULL;
output = -1;
outname = NULL;
- if (strncmp(target_filename, "MTD:", 4) == 0) {
+ if (strncmp(target_filename, "MTD:", 4) == 0 ||
+ strncmp(target_filename, "EMMC:", 5) == 0) {
// We store the decoded output in memory.
msi.buffer = malloc(target_size);
if (msi.buffer == NULL) {
@@ -779,8 +852,8 @@ int applypatch(const char* source_filename,
}
if (output < 0) {
- // Copy the temp file to the MTD partition.
- if (WriteToMTDPartition(msi.buffer, msi.pos, target_filename) != 0) {
+ // Copy the temp file to the partition.
+ if (WriteToPartition(msi.buffer, msi.pos, target_filename) != 0) {
printf("write of patched data to %s failed\n", target_filename);
return 1;
}
diff --git a/common.h b/common.h
index 1182d77aa..333417f39 100644
--- a/common.h
+++ b/common.h
@@ -36,7 +36,7 @@ void ui_print(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
// Display some header text followed by a menu of items, which appears
// at the top of the screen (in place of any scrolling ui_print()
// output, if necessary).
-void ui_start_menu(char** headers, char** items);
+void ui_start_menu(char** headers, char** items, int initial_selection);
// Set the menu highlight to the given index, and return it (capped to
// the range [0..numitems).
int ui_menu_select(int sel);
@@ -72,12 +72,12 @@ void ui_show_indeterminate_progress();
void ui_reset_progress();
#define LOGE(...) ui_print("E:" __VA_ARGS__)
-#define LOGW(...) fprintf(stderr, "W:" __VA_ARGS__)
-#define LOGI(...) fprintf(stderr, "I:" __VA_ARGS__)
+#define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__)
+#define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__)
#if 0
-#define LOGV(...) fprintf(stderr, "V:" __VA_ARGS__)
-#define LOGD(...) fprintf(stderr, "D:" __VA_ARGS__)
+#define LOGV(...) fprintf(stdout, "V:" __VA_ARGS__)
+#define LOGD(...) fprintf(stdout, "D:" __VA_ARGS__)
#else
#define LOGV(...) do {} while (0)
#define LOGD(...) do {} while (0)
diff --git a/default_recovery_ui.c b/default_recovery_ui.c
index 409d67934..ce12787fe 100644
--- a/default_recovery_ui.c
+++ b/default_recovery_ui.c
@@ -24,7 +24,7 @@ char* MENU_HEADERS[] = { "Android system recovery utility",
NULL };
char* MENU_ITEMS[] = { "reboot system now",
- "apply sdcard:update.zip",
+ "apply update from sdcard",
"wipe data/factory reset",
"wipe cache partition",
NULL };
diff --git a/install.c b/install.c
index 35ba6ca70..20e899854 100644
--- a/install.c
+++ b/install.c
@@ -109,7 +109,7 @@ try_update_binary(const char *path, ZipArchive *zip) {
if (pid == 0) {
close(pipefd[0]);
execv(binary, args);
- fprintf(stderr, "E:Can't run %s (%s)\n", binary, strerror(errno));
+ fprintf(stdout, "E:Can't run %s (%s)\n", binary, strerror(errno));
_exit(-1);
}
close(pipefd[1]);
diff --git a/recovery.c b/recovery.c
index 04bf657d5..6c4507f0d 100644
--- a/recovery.c
+++ b/recovery.c
@@ -28,6 +28,7 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
+#include <dirent.h>
#include "bootloader.h"
#include "common.h"
@@ -51,7 +52,7 @@ static const struct option OPTIONS[] = {
static const char *COMMAND_FILE = "CACHE:recovery/command";
static const char *INTENT_FILE = "CACHE:recovery/intent";
static const char *LOG_FILE = "CACHE:recovery/log";
-static const char *SDCARD_PACKAGE_FILE = "SDCARD:update.zip";
+static const char *SDCARD_ROOT = "SDCARD:";
static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log";
static const char *SIDELOAD_TEMP_DIR = "TMP:sideload";
@@ -405,7 +406,7 @@ copy_sideloaded_package(const char* original_root_path) {
}
static char**
-prepend_title(char** headers) {
+prepend_title(const char** headers) {
char* title[] = { "Android system recovery <"
EXPAND(RECOVERY_API_VERSION) "e>",
"",
@@ -428,13 +429,14 @@ prepend_title(char** headers) {
}
static int
-get_menu_selection(char** headers, char** items, int menu_only) {
+get_menu_selection(char** headers, char** items, int menu_only,
+ int initial_selection) {
// throw away keys pressed previously, so user doesn't
// accidentally trigger menu items.
ui_clear_key_queue();
- ui_start_menu(headers, items);
- int selected = 0;
+ ui_start_menu(headers, items, initial_selection);
+ int selected = initial_selection;
int chosen_item = -1;
while (chosen_item < 0) {
@@ -468,6 +470,127 @@ get_menu_selection(char** headers, char** items, int menu_only) {
return chosen_item;
}
+static int compare_string(const void* a, const void* b) {
+ return strcmp(*(const char**)a, *(const char**)b);
+}
+
+static int
+sdcard_directory(const char* root_path) {
+ // Mount the sdcard when the package selection menu is enabled so
+ // you can "adb push" packages to the sdcard and immediately
+ // install them.
+ ensure_root_path_mounted(SDCARD_ROOT);
+
+ const char* MENU_HEADERS[] = { "Choose a package to install:",
+ root_path,
+ "",
+ NULL };
+ DIR* d;
+ struct dirent* de;
+ char path[PATH_MAX];
+ d = opendir(translate_root_path(root_path, path, sizeof(path)));
+ if (d == NULL) {
+ LOGE("error opening %s: %s\n", path, strerror(errno));
+ return 0;
+ }
+
+ char** headers = prepend_title(MENU_HEADERS);
+
+ int d_size = 0;
+ int d_alloc = 10;
+ char** dirs = malloc(d_alloc * sizeof(char*));
+ int z_size = 1;
+ int z_alloc = 10;
+ char** zips = malloc(z_alloc * sizeof(char*));
+ zips[0] = strdup("../");
+
+ while ((de = readdir(d)) != NULL) {
+ int name_len = strlen(de->d_name);
+
+ if (de->d_type == DT_DIR) {
+ // skip "." and ".." entries
+ if (name_len == 1 && de->d_name[0] == '.') continue;
+ if (name_len == 2 && de->d_name[0] == '.' &&
+ de->d_name[1] == '.') continue;
+
+ if (d_size >= d_alloc) {
+ d_alloc *= 2;
+ dirs = realloc(dirs, d_alloc * sizeof(char*));
+ }
+ dirs[d_size] = malloc(name_len + 2);
+ strcpy(dirs[d_size], de->d_name);
+ dirs[d_size][name_len] = '/';
+ dirs[d_size][name_len+1] = '\0';
+ ++d_size;
+ } else if (de->d_type == DT_REG &&
+ name_len >= 4 &&
+ strncasecmp(de->d_name + (name_len-4), ".zip", 4) == 0) {
+ if (z_size >= z_alloc) {
+ z_alloc *= 2;
+ zips = realloc(zips, z_alloc * sizeof(char*));
+ }
+ zips[z_size++] = strdup(de->d_name);
+ }
+ }
+ closedir(d);
+
+ qsort(dirs, d_size, sizeof(char*), compare_string);
+ qsort(zips, z_size, sizeof(char*), compare_string);
+
+ // append dirs to the zips list
+ if (d_size + z_size + 1 > z_alloc) {
+ z_alloc = d_size + z_size + 1;
+ zips = realloc(zips, z_alloc * sizeof(char*));
+ }
+ memcpy(zips + z_size, dirs, d_size * sizeof(char*));
+ free(dirs);
+ z_size += d_size;
+ zips[z_size] = NULL;
+
+ int result = INSTALL_CORRUPT;
+ int chosen_item = 0;
+ do {
+ chosen_item = get_menu_selection(headers, zips, 1, chosen_item);
+
+ char* item = zips[chosen_item];
+ int item_len = strlen(item);
+ if (chosen_item == 0) { // item 0 is always "../"
+ // go up but continue browsing (if the caller is sdcard_directory)
+ result = -1;
+ break;
+ } else if (item[item_len-1] == '/') {
+ // recurse down into a subdirectory
+ char new_path[PATH_MAX];
+ strlcpy(new_path, root_path, PATH_MAX);
+ strlcat(new_path, item, PATH_MAX);
+ result = sdcard_directory(new_path);
+ if (result >= 0) break;
+ } else {
+ // selected a zip file: attempt to install it, and return
+ // the status to the caller.
+ char new_path[PATH_MAX];
+ strlcpy(new_path, root_path, PATH_MAX);
+ strlcat(new_path, item, PATH_MAX);
+
+ ui_print("\n-- Install %s ...\n", new_path);
+ char* copy = copy_sideloaded_package(new_path);
+ if (copy != NULL) {
+ set_sdcard_update_bootloader_message();
+ result = install_package(copy);
+ free(copy);
+ }
+ break;
+ }
+ } while (true);
+
+ int i;
+ for (i = 0; i < z_size; ++i) free(zips[i]);
+ free(zips);
+ free(headers);
+
+ return result;
+}
+
static void
wipe_data(int confirm) {
if (confirm) {
@@ -478,7 +601,7 @@ wipe_data(int confirm) {
" THIS CAN NOT BE UNDONE.",
"",
NULL };
- title_headers = prepend_title(headers);
+ title_headers = prepend_title((const char**)headers);
}
char* items[] = { " No",
@@ -494,7 +617,7 @@ wipe_data(int confirm) {
" No",
NULL };
- int chosen_item = get_menu_selection(title_headers, items, 1);
+ int chosen_item = get_menu_selection(title_headers, items, 1, 0);
if (chosen_item != 7) {
return;
}
@@ -509,13 +632,13 @@ wipe_data(int confirm) {
static void
prompt_and_wait() {
- char** headers = prepend_title(MENU_HEADERS);
+ char** headers = prepend_title((const char**)MENU_HEADERS);
for (;;) {
finish_recovery(NULL);
ui_reset_progress();
- int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0);
+ int chosen_item = get_menu_selection(headers, MENU_ITEMS, 0, 0);
// device-specific code may take some action here. It may
// return one of the core actions handled in the switch
@@ -539,21 +662,17 @@ prompt_and_wait() {
break;
case ITEM_APPLY_SDCARD:
- ui_print("\n-- Install from sdcard...\n");
- int status = INSTALL_CORRUPT;
- char* copy = copy_sideloaded_package(SDCARD_PACKAGE_FILE);
- if (copy != NULL) {
- set_sdcard_update_bootloader_message();
- status = install_package(copy);
- free(copy);
- }
- if (status != INSTALL_SUCCESS) {
- ui_set_background(BACKGROUND_ICON_ERROR);
- ui_print("Installation aborted.\n");
- } else if (!ui_text_visible()) {
- return; // reboot if logs aren't visible
- } else {
- ui_print("\nInstall from sdcard complete.\n");
+ ;
+ int status = sdcard_directory(SDCARD_ROOT);
+ if (status >= 0) {
+ if (status != INSTALL_SUCCESS) {
+ ui_set_background(BACKGROUND_ICON_ERROR);
+ ui_print("Installation aborted.\n");
+ } else if (!ui_text_visible()) {
+ return; // reboot if logs aren't visible
+ } else {
+ ui_print("\nInstall from sdcard complete.\n");
+ }
}
break;
}
@@ -562,7 +681,7 @@ prompt_and_wait() {
static void
print_property(const char *key, const char *name, void *cookie) {
- fprintf(stderr, "%s=%s\n", key, name);
+ printf("%s=%s\n", key, name);
}
int
@@ -572,7 +691,7 @@ main(int argc, char **argv) {
// If these fail, there's not really anywhere to complain...
freopen(TEMPORARY_LOG_FILE, "a", stdout); setbuf(stdout, NULL);
freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL);
- fprintf(stderr, "Starting recovery on %s", ctime(&start));
+ printf("Starting recovery on %s", ctime(&start));
ui_init();
get_args(&argc, &argv);
@@ -602,14 +721,14 @@ main(int argc, char **argv) {
device_recovery_start();
- fprintf(stderr, "Command:");
+ printf("Command:");
for (arg = 0; arg < argc; arg++) {
- fprintf(stderr, " \"%s\"", argv[arg]);
+ printf(" \"%s\"", argv[arg]);
}
- fprintf(stderr, "\n\n");
+ printf("\n\n");
property_list(print_property, NULL);
- fprintf(stderr, "\n");
+ printf("\n");
int status = INSTALL_SUCCESS;
@@ -665,7 +784,9 @@ main(int argc, char **argv) {
}
if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR);
- if (status != INSTALL_SUCCESS || ui_text_visible()) prompt_and_wait();
+ if (status != INSTALL_SUCCESS || ui_text_visible()) {
+ prompt_and_wait();
+ }
// Otherwise, get ready to boot the main system...
finish_recovery(send_intent);
diff --git a/roots.c b/roots.c
index d5754db3a..762bdf382 100644
--- a/roots.c
+++ b/roots.c
@@ -23,6 +23,11 @@
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
+
+#ifdef USE_EXT4
+#include "make_ext4fs.h"
+#endif
+
#include "minzip/Zip.h"
#include "roots.h"
#include "common.h"
@@ -46,8 +51,6 @@ static const char g_ramdisk[] = "@\0g_ramdisk";
static RootInfo g_roots[] = {
{ "BOOT:", g_mtd_device, NULL, "boot", NULL, g_raw },
- { "CACHE:", g_mtd_device, NULL, "cache", "/cache", "yaffs2" },
- { "DATA:", g_mtd_device, NULL, "userdata", "/data", "yaffs2" },
{ "MISC:", g_mtd_device, NULL, "misc", NULL, g_raw },
{ "PACKAGE:", NULL, NULL, NULL, NULL, g_package_file },
{ "RECOVERY:", g_mtd_device, NULL, "recovery", "/", g_raw },
@@ -55,6 +58,17 @@ static RootInfo g_roots[] = {
{ "SYSTEM:", g_mtd_device, NULL, "system", "/system", "yaffs2" },
{ "MBM:", g_mtd_device, NULL, "mbm", NULL, g_raw },
{ "TMP:", NULL, NULL, NULL, "/tmp", g_ramdisk },
+
+#ifdef USE_EXT4
+ { "CACHE:", "/dev/block/platform/sdhci-tegra.3/by-name/cache", NULL, NULL,
+ "/cache", "ext4" },
+ { "DATA:", "/dev/block/platform/sdhci-tegra.3/by-name/userdata", NULL, NULL,
+ "/data", "ext4" },
+#else
+ { "CACHE:", g_mtd_device, NULL, "cache", "/cache", "yaffs2" },
+ { "DATA:", g_mtd_device, NULL, "userdata", "/data", "yaffs2" },
+#endif
+
};
#define NUM_ROOTS (sizeof(g_roots) / sizeof(g_roots[0]))
@@ -252,7 +266,7 @@ ensure_root_path_mounted(const char *root_path)
mkdir(info->mount_point, 0755); // in case it doesn't already exist
if (mount(info->device, info->mount_point, info->filesystem,
- MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
+ MS_NOATIME | MS_NODEV | MS_NODIRATIME, "")) {
if (info->device2 == NULL) {
LOGE("Can't mount %s\n(%s)\n", info->device, strerror(errno));
return -1;
@@ -368,7 +382,21 @@ format_root_device(const char *root)
}
}
}
+
+#ifdef USE_EXT4
+ if (strcmp(info->filesystem, "ext4") == 0) {
+ reset_ext4fs_info();
+ int result = make_ext4fs(info->device, NULL, NULL, 0, 0);
+ if (result != 0) {
+ LOGW("make_ext4fs failed: %d\n", result);
+ return -1;
+ }
+ return 0;
+ }
+#endif
+
//TODO: handle other device types (sdcard, etc.)
- LOGW("format_root_device: can't handle non-mtd device \"%s\"\n", root);
+
+ LOGW("format_root_device: unknown device \"%s\"\n", root);
return -1;
}
diff --git a/ui.c b/ui.c
index 01a005f80..ee6a0c5ca 100644
--- a/ui.c
+++ b/ui.c
@@ -29,7 +29,7 @@
#include "minui/minui.h"
#include "recovery_ui.h"
-#define MAX_COLS 64
+#define MAX_COLS 96
#define MAX_ROWS 32
#define CHAR_WIDTH 10
@@ -404,7 +404,7 @@ void ui_print(const char *fmt, ...)
vsnprintf(buf, 256, fmt, ap);
va_end(ap);
- fputs(buf, stderr);
+ fputs(buf, stdout);
// This can get called before ui_init(), so be careful.
pthread_mutex_lock(&gUpdateMutex);
@@ -425,7 +425,7 @@ void ui_print(const char *fmt, ...)
pthread_mutex_unlock(&gUpdateMutex);
}
-void ui_start_menu(char** headers, char** items) {
+void ui_start_menu(char** headers, char** items, int initial_selection) {
int i;
pthread_mutex_lock(&gUpdateMutex);
if (text_rows > 0 && text_cols > 0) {
@@ -442,7 +442,7 @@ void ui_start_menu(char** headers, char** items) {
}
menu_items = i - menu_top;
show_menu = 1;
- menu_sel = 0;
+ menu_sel = initial_selection;
update_screen_locked();
}
pthread_mutex_unlock(&gUpdateMutex);
diff --git a/updater/Android.mk b/updater/Android.mk
index d4a4e332d..dcc6a49ab 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -18,7 +18,13 @@ LOCAL_MODULE_TAGS := eng
LOCAL_SRC_FILES := $(updater_src_files)
-LOCAL_STATIC_LIBRARIES := $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
+ifeq ($(TARGET_USERIMAGES_USE_EXT4), true)
+LOCAL_CFLAGS += -DUSE_EXT4
+LOCAL_C_INCLUDES += system/extras/ext4_utils
+LOCAL_STATIC_LIBRARIES += libext4_utils libz
+endif
+
+LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS)
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
diff --git a/updater/install.c b/updater/install.c
index e869134be..167b40204 100644
--- a/updater/install.c
+++ b/updater/install.c
@@ -36,24 +36,35 @@
#include "updater.h"
#include "applypatch/applypatch.h"
-// mount(type, location, mount_point)
+#ifdef USE_EXT4
+#include "make_ext4fs.h"
+#endif
+
+// mount(fs_type, partition_type, location, mount_point)
//
-// what: type="MTD" location="<partition>" to mount a yaffs2 filesystem
-// type="vfat" location="/dev/block/<whatever>" to mount a device
+// fs_type="yaffs2" partition_type="MTD" location=partition
+// fs_type="ext4" partition_type="EMMC" location=device
Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
- if (argc != 3) {
- return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
+ if (argc != 4) {
+ return ErrorAbort(state, "%s() expects 4 args, got %d", name, argc);
}
- char* type;
+ char* fs_type;
+ char* partition_type;
char* location;
char* mount_point;
- if (ReadArgs(state, argv, 3, &type, &location, &mount_point) < 0) {
+ if (ReadArgs(state, argv, 4, &fs_type, &partition_type,
+ &location, &mount_point) < 0) {
return NULL;
}
- if (strlen(type) == 0) {
- ErrorAbort(state, "type argument to %s() can't be empty", name);
+ if (strlen(fs_type) == 0) {
+ ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
+ goto done;
+ }
+ if (strlen(partition_type) == 0) {
+ ErrorAbort(state, "partition_type argument to %s() can't be empty",
+ name);
goto done;
}
if (strlen(location) == 0) {
@@ -67,7 +78,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
mkdir(mount_point, 0755);
- if (strcmp(type, "MTD") == 0) {
+ if (strcmp(partition_type, "MTD") == 0) {
mtd_scan_partitions();
const MtdPartition* mtd;
mtd = mtd_find_partition_by_name(location);
@@ -77,7 +88,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
result = strdup("");
goto done;
}
- if (mtd_mount_partition(mtd, mount_point, "yaffs2", 0 /* rw */) != 0) {
+ if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) {
fprintf(stderr, "mtd mount of %s failed: %s\n",
location, strerror(errno));
result = strdup("");
@@ -85,7 +96,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
}
result = mount_point;
} else {
- if (mount(location, mount_point, type,
+ if (mount(location, mount_point, fs_type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) {
fprintf(stderr, "%s: failed to mount %s at %s: %s\n",
name, location, mount_point, strerror(errno));
@@ -96,7 +107,8 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) {
}
done:
- free(type);
+ free(fs_type);
+ free(partition_type);
free(location);
if (result != mount_point) free(mount_point);
return StringValue(result);
@@ -162,22 +174,29 @@ done:
}
-// format(type, location)
+// format(fs_type, partition_type, location)
//
-// type="MTD" location=partition
+// fs_type="yaffs2" partition_type="MTD" location=partition
+// fs_type="ext4" partition_type="EMMC" location=device
Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
char* result = NULL;
- if (argc != 2) {
- return ErrorAbort(state, "%s() expects 2 args, got %d", name, argc);
+ if (argc != 3) {
+ return ErrorAbort(state, "%s() expects 3 args, got %d", name, argc);
}
- char* type;
+ char* fs_type;
+ char* partition_type;
char* location;
- if (ReadArgs(state, argv, 2, &type, &location) < 0) {
+ if (ReadArgs(state, argv, 3, &fs_type, &partition_type, &location) < 0) {
return NULL;
}
- if (strlen(type) == 0) {
- ErrorAbort(state, "type argument to %s() can't be empty", name);
+ if (strlen(fs_type) == 0) {
+ ErrorAbort(state, "fs_type argument to %s() can't be empty", name);
+ goto done;
+ }
+ if (strlen(partition_type) == 0) {
+ ErrorAbort(state, "partition_type argument to %s() can't be empty",
+ name);
goto done;
}
if (strlen(location) == 0) {
@@ -185,7 +204,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
- if (strcmp(type, "MTD") == 0) {
+ if (strcmp(partition_type, "MTD") == 0) {
mtd_scan_partitions();
const MtdPartition* mtd = mtd_find_partition_by_name(location);
if (mtd == NULL) {
@@ -212,12 +231,26 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) {
goto done;
}
result = location;
+#ifdef USE_EXT4
+ } else if (strcmp(fs_type, "ext4") == 0) {
+ reset_ext4fs_info();
+ int status = make_ext4fs(location, NULL, NULL, 0, 0);
+ if (status != 0) {
+ fprintf(stderr, "%s: make_ext4fs failed (%d) on %s",
+ name, status, location);
+ result = strdup("");
+ goto done;
+ }
+ result = location;
+#endif
} else {
- fprintf(stderr, "%s: unsupported type \"%s\"", name, type);
+ fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"",
+ name, fs_type, partition_type);
}
done:
- free(type);
+ free(fs_type);
+ free(partition_type);
if (result != location) free(location);
return StringValue(result);
}