summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--CleanSpec.mk1
-rw-r--r--applypatch/applypatch.c27
-rw-r--r--bootloader.cpp43
-rw-r--r--common.h25
-rw-r--r--fonts/12x22.pngbin0 -> 14431 bytes
-rw-r--r--fonts/18x32.pngbin0 -> 24437 bytes
-rw-r--r--fonts/OFL.txt93
-rw-r--r--fonts/README6
-rw-r--r--install.cpp100
-rw-r--r--minui/graphics.c65
-rw-r--r--minui/minui.h2
-rw-r--r--minui/resources.c20
-rw-r--r--minzip/Zip.c6
-rw-r--r--mtdutils/Android.mk2
-rw-r--r--recovery.cpp56
-rw-r--r--roots.cpp140
-rw-r--r--screen_ui.cpp58
-rw-r--r--screen_ui.h3
-rw-r--r--updater/Android.mk2
-rw-r--r--verifier.cpp102
-rw-r--r--verifier.h2
-rw-r--r--verifier_test.cpp25
23 files changed, 451 insertions, 330 deletions
diff --git a/Android.mk b/Android.mk
index f4ecdb5dd..075fa2cfe 100644
--- a/Android.mk
+++ b/Android.mk
@@ -32,6 +32,7 @@ LOCAL_MODULE := recovery
LOCAL_FORCE_STATIC_EXECUTABLE := true
RECOVERY_API_VERSION := 3
+RECOVERY_FSTAB_VERSION := 2
LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION)
LOCAL_STATIC_LIBRARIES := \
@@ -45,7 +46,9 @@ LOCAL_STATIC_LIBRARIES := \
libminui \
libpixelflinger_static \
libpng \
+ libfs_mgr \
libcutils \
+ liblog \
libselinux \
libstdc++ \
libm \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index b84e1b65e..ecf89ae75 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -47,3 +47,4 @@
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/recovery_intermediates)
diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c
index 7b8a010e3..69f8633ab 100644
--- a/applypatch/applypatch.c
+++ b/applypatch/applypatch.c
@@ -585,6 +585,14 @@ int CacheSizeCheck(size_t bytes) {
}
}
+static void print_short_sha1(const uint8_t sha1[SHA_DIGEST_SIZE]) {
+ int i;
+ const char* hex = "0123456789abcdef";
+ for (i = 0; i < 4; ++i) {
+ putchar(hex[(sha1[i]>>4) & 0xf]);
+ putchar(hex[sha1[i] & 0xf]);
+ }
+}
// This function applies binary patches to files in a way that is safe
// (the original file is not touched until we have the desired
@@ -620,7 +628,7 @@ int applypatch(const char* source_filename,
char** const patch_sha1_str,
Value** patch_data,
Value* bonus_data) {
- printf("\napplying patch to %s\n", source_filename);
+ printf("patch %s: ", source_filename);
if (target_filename[0] == '-' &&
target_filename[1] == '\0') {
@@ -646,8 +654,9 @@ int applypatch(const char* source_filename,
if (memcmp(source_file.sha1, target_sha1, SHA_DIGEST_SIZE) == 0) {
// The early-exit case: the patch was already applied, this file
// has the desired hash, nothing for us to do.
- printf("\"%s\" is already target; no patch needed\n",
- target_filename);
+ printf("already ");
+ print_short_sha1(target_sha1);
+ putchar('\n');
free(source_file.data);
return 0;
}
@@ -769,8 +778,10 @@ static int GenerateTarget(FileContents* source_file,
enough_space =
(free_space > (256 << 10)) && // 256k (two-block) minimum
(free_space > (target_size * 3 / 2)); // 50% margin of error
- printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
- (long)target_size, (long)free_space, retry, enough_space);
+ if (!enough_space) {
+ printf("target %ld bytes; free space %ld bytes; retry %d; enough %d\n",
+ (long)target_size, (long)free_space, retry, enough_space);
+ }
}
if (!enough_space) {
@@ -805,7 +816,7 @@ static int GenerateTarget(FileContents* source_file,
unlink(source_filename);
size_t free_space = FreeSpaceForFile(target_fs);
- printf("(now %ld bytes free for target)\n", (long)free_space);
+ printf("(now %ld bytes free for target) ", (long)free_space);
}
}
@@ -901,6 +912,10 @@ static int GenerateTarget(FileContents* source_file,
if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
printf("patch did not produce expected sha1\n");
return 1;
+ } else {
+ printf("now ");
+ print_short_sha1(target_sha1);
+ putchar('\n');
}
if (output < 0) {
diff --git a/bootloader.cpp b/bootloader.cpp
index baaddc55f..600d238f5 100644
--- a/bootloader.cpp
+++ b/bootloader.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <fs_mgr.h>
#include "bootloader.h"
#include "common.h"
#include "mtdutils/mtdutils.h"
@@ -71,22 +72,22 @@ static int get_bootloader_message_mtd(struct bootloader_message *out,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
- const MtdPartition *part = mtd_find_partition_by_name(v->device);
+ const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
- LOGE("Can't find %s\n", v->device);
+ LOGE("Can't find %s\n", v->blk_device);
return -1;
}
MtdReadContext *read = mtd_read_partition(part);
if (read == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
const ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
- if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
+ if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
@@ -97,22 +98,22 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
const Volume* v) {
size_t write_size;
mtd_scan_partitions();
- const MtdPartition *part = mtd_find_partition_by_name(v->device);
+ const MtdPartition *part = mtd_find_partition_by_name(v->blk_device);
if (part == NULL || mtd_partition_info(part, NULL, NULL, &write_size)) {
- LOGE("Can't find %s\n", v->device);
+ LOGE("Can't find %s\n", v->blk_device);
return -1;
}
MtdReadContext *read = mtd_read_partition(part);
if (read == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
ssize_t size = write_size * MISC_PAGES;
char data[size];
ssize_t r = mtd_read_data(read, data, size);
- if (r != size) LOGE("Can't read %s\n(%s)\n", v->device, strerror(errno));
+ if (r != size) LOGE("Can't read %s\n(%s)\n", v->blk_device, strerror(errno));
mtd_read_close(read);
if (r != size) return -1;
@@ -120,16 +121,16 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in,
MtdWriteContext *write = mtd_write_partition(part);
if (write == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
if (mtd_write_data(write, data, size) != size) {
- LOGE("Can't write %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't write %s\n(%s)\n", v->blk_device, strerror(errno));
mtd_write_close(write);
return -1;
}
if (mtd_write_close(write)) {
- LOGE("Can't finish %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't finish %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
@@ -161,20 +162,20 @@ static void wait_for_device(const char* fn) {
static int get_bootloader_message_block(struct bootloader_message *out,
const Volume* v) {
- wait_for_device(v->device);
- FILE* f = fopen(v->device, "rb");
+ wait_for_device(v->blk_device);
+ FILE* f = fopen(v->blk_device, "rb");
if (f == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
struct bootloader_message temp;
int count = fread(&temp, sizeof(temp), 1, f);
if (count != 1) {
- LOGE("Failed reading %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Failed reading %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
- LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
memcpy(out, &temp, sizeof(temp));
@@ -183,19 +184,19 @@ static int get_bootloader_message_block(struct bootloader_message *out,
static int set_bootloader_message_block(const struct bootloader_message *in,
const Volume* v) {
- wait_for_device(v->device);
- FILE* f = fopen(v->device, "wb");
+ wait_for_device(v->blk_device);
+ FILE* f = fopen(v->blk_device, "wb");
if (f == NULL) {
- LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Can't open %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
int count = fwrite(in, sizeof(*in), 1, f);
if (count != 1) {
- LOGE("Failed writing %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Failed writing %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
if (fclose(f) != 0) {
- LOGE("Failed closing %s\n(%s)\n", v->device, strerror(errno));
+ LOGE("Failed closing %s\n(%s)\n", v->blk_device, strerror(errno));
return -1;
}
return 0;
diff --git a/common.h b/common.h
index a1168cdbb..768f499f9 100644
--- a/common.h
+++ b/common.h
@@ -18,13 +18,13 @@
#define RECOVERY_COMMON_H
#include <stdio.h>
+#include <stdarg.h>
#ifdef __cplusplus
extern "C" {
#endif
-// TODO: restore ui_print for LOGE
-#define LOGE(...) fprintf(stdout, "E:" __VA_ARGS__)
+#define LOGE(...) ui_print("E:" __VA_ARGS__)
#define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__)
#define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__)
@@ -39,28 +39,13 @@ extern "C" {
#define STRINGIFY(x) #x
#define EXPAND(x) STRINGIFY(x)
-typedef struct {
- const char* mount_point; // eg. "/cache". must live in the root directory.
-
- const char* fs_type; // "yaffs2" or "ext4" or "vfat"
-
- const char* device; // MTD partition name if fs_type == "yaffs"
- // block device if fs_type == "ext4" or "vfat"
-
- const char* device2; // alternative device to try if fs_type
- // == "ext4" or "vfat" and mounting
- // 'device' fails
-
- long long length; // (ext4 partition only) when
- // formatting, size to use for the
- // partition. 0 or negative number
- // means to format all but the last
- // (that much).
-} Volume;
+typedef struct fstab_rec Volume;
// fopen a file, mounting volumes and making parent dirs as necessary.
FILE* fopen_path(const char *path, const char *mode);
+void ui_print(const char* format, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/fonts/12x22.png b/fonts/12x22.png
new file mode 100644
index 000000000..ae826bebe
--- /dev/null
+++ b/fonts/12x22.png
Binary files differ
diff --git a/fonts/18x32.png b/fonts/18x32.png
new file mode 100644
index 000000000..d95408a93
--- /dev/null
+++ b/fonts/18x32.png
Binary files differ
diff --git a/fonts/OFL.txt b/fonts/OFL.txt
new file mode 100644
index 000000000..b14edde76
--- /dev/null
+++ b/fonts/OFL.txt
@@ -0,0 +1,93 @@
+Copyright (c) 2011, Raph Levien (firstname.lastname@gmail.com), Copyright (c) 2012, Cyreal (cyreal.org)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/fonts/README b/fonts/README
new file mode 100644
index 000000000..d0748d2f7
--- /dev/null
+++ b/fonts/README
@@ -0,0 +1,6 @@
+The images in this directory were generated using the font
+Inconsolata, which is released under the OFL license and was obtained
+from:
+
+ https://code.google.com/p/googlefontdirectory/source/browse/ofl/inconsolata/
+
diff --git a/install.cpp b/install.cpp
index b8f478130..0f3298f1d 100644
--- a/install.cpp
+++ b/install.cpp
@@ -174,106 +174,6 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) {
return INSTALL_SUCCESS;
}
-// Reads a file containing one or more public keys as produced by
-// DumpPublicKey: this is an RSAPublicKey struct as it would appear
-// as a C source literal, eg:
-//
-// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
-//
-// For key versions newer than the original 2048-bit e=3 keys
-// supported by Android, the string is preceded by a version
-// identifier, eg:
-//
-// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
-//
-// (Note that the braces and commas in this example are actual
-// characters the parser expects to find in the file; the ellipses
-// indicate more numbers omitted from this example.)
-//
-// The file may contain multiple keys in this format, separated by
-// commas. The last key must not be followed by a comma.
-//
-// Returns NULL if the file failed to parse, or if it contain zero keys.
-static RSAPublicKey*
-load_keys(const char* filename, int* numKeys) {
- RSAPublicKey* out = NULL;
- *numKeys = 0;
-
- FILE* f = fopen(filename, "r");
- if (f == NULL) {
- LOGE("opening %s: %s\n", filename, strerror(errno));
- goto exit;
- }
-
- {
- int i;
- bool done = false;
- while (!done) {
- ++*numKeys;
- out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
- RSAPublicKey* key = out + (*numKeys - 1);
-
- char start_char;
- if (fscanf(f, " %c", &start_char) != 1) goto exit;
- if (start_char == '{') {
- // a version 1 key has no version specifier.
- key->exponent = 3;
- } else if (start_char == 'v') {
- int version;
- if (fscanf(f, "%d {", &version) != 1) goto exit;
- if (version == 2) {
- key->exponent = 65537;
- } else {
- goto exit;
- }
- }
-
- if (fscanf(f, " %i , 0x%x , { %u",
- &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
- goto exit;
- }
- if (key->len != RSANUMWORDS) {
- LOGE("key length (%d) does not match expected size\n", key->len);
- goto exit;
- }
- for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
- }
- if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
- for (i = 1; i < key->len; ++i) {
- if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
- }
- fscanf(f, " } } ");
-
- // if the line ends in a comma, this file has more keys.
- switch (fgetc(f)) {
- case ',':
- // more keys to come.
- break;
-
- case EOF:
- done = true;
- break;
-
- default:
- LOGE("unexpected character between keys\n");
- goto exit;
- }
-
- LOGI("read key e=%d\n", key->exponent);
- }
- }
-
- fclose(f);
- return out;
-
-exit:
- if (f) fclose(f);
- free(out);
- *numKeys = 0;
- return NULL;
-}
-
static int
really_install_package(const char *path, int* wipe_cache)
{
diff --git a/minui/graphics.c b/minui/graphics.c
index 747b2dbc6..4968eac7a 100644
--- a/minui/graphics.c
+++ b/minui/graphics.c
@@ -47,10 +47,9 @@
#define NUM_BUFFERS 2
typedef struct {
- GGLSurface texture;
+ GGLSurface* texture;
unsigned cwidth;
unsigned cheight;
- unsigned ascent;
} GRFont;
static GRFont *gr_font = 0;
@@ -224,18 +223,20 @@ void gr_font_size(int *x, int *y)
*y = gr_font->cheight;
}
-int gr_text(int x, int y, const char *s)
+int gr_text(int x, int y, const char *s, int bold)
{
GGLContext *gl = gr_context;
GRFont *font = gr_font;
unsigned off;
+ if (!font->texture) return x;
+
+ bold = bold && (font->texture->height != font->cheight);
+
x += overscan_offset_x;
y += overscan_offset_y;
- y -= font->ascent;
-
- gl->bindTexture(gl, &font->texture);
+ gl->bindTexture(gl, font->texture);
gl->texEnvi(gl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
gl->texGeni(gl, GGL_S, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
gl->texGeni(gl, GGL_T, GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
@@ -244,7 +245,8 @@ int gr_text(int x, int y, const char *s)
while((off = *s++)) {
off -= 32;
if (off < 96) {
- gl->texCoord2i(gl, (off * font->cwidth) - x, 0 - y);
+ gl->texCoord2i(gl, (off * font->cwidth) - x,
+ (bold ? font->cheight : 0) - y);
gl->recti(gl, x, y, x + font->cwidth, y + font->cheight);
}
x += font->cwidth;
@@ -322,31 +324,40 @@ unsigned int gr_get_height(gr_surface surface) {
static void gr_init_font(void)
{
- GGLSurface *ftex;
- unsigned char *bits, *rle;
- unsigned char *in, data;
-
gr_font = calloc(sizeof(*gr_font), 1);
- ftex = &gr_font->texture;
-
- bits = malloc(font.width * font.height);
- ftex->version = sizeof(*ftex);
- ftex->width = font.width;
- ftex->height = font.height;
- ftex->stride = font.width;
- ftex->data = (void*) bits;
- ftex->format = GGL_PIXEL_FORMAT_A_8;
+ int res = res_create_surface("font", (void**)&(gr_font->texture));
+ if (res == 0) {
+ // The font image should be a 96x2 array of character images. The
+ // columns are the printable ASCII characters 0x20 - 0x7f. The
+ // top row is regular text; the bottom row is bold.
+ gr_font->cwidth = gr_font->texture->width / 96;
+ gr_font->cheight = gr_font->texture->height / 2;
+ } else {
+ printf("failed to read font: res=%d\n", res);
+
+ // fall back to the compiled-in font.
+ gr_font->texture = malloc(sizeof(*gr_font->texture));
+ gr_font->texture->width = font.width;
+ gr_font->texture->height = font.height;
+ gr_font->texture->stride = font.width;
+
+ unsigned char* bits = malloc(font.width * font.height);
+ gr_font->texture->data = (void*) bits;
+
+ unsigned char data;
+ unsigned char* in = font.rundata;
+ while((data = *in++)) {
+ memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
+ bits += (data & 0x7f);
+ }
- in = font.rundata;
- while((data = *in++)) {
- memset(bits, (data & 0x80) ? 255 : 0, data & 0x7f);
- bits += (data & 0x7f);
+ gr_font->cwidth = font.cwidth;
+ gr_font->cheight = font.cheight;
}
- gr_font->cwidth = font.cwidth;
- gr_font->cheight = font.cheight;
- gr_font->ascent = font.cheight - 2;
+ // interpret the grayscale as alpha
+ gr_font->texture->format = GGL_PIXEL_FORMAT_A_8;
}
int gr_init(void)
diff --git a/minui/minui.h b/minui/minui.h
index bc43bb596..1b8dd059b 100644
--- a/minui/minui.h
+++ b/minui/minui.h
@@ -37,7 +37,7 @@ void gr_fb_blank(bool blank);
void gr_color(unsigned char r, unsigned char g, unsigned char b, unsigned char a);
void gr_fill(int x1, int y1, int x2, int y2);
-int gr_text(int x, int y, const char *s);
+int gr_text(int x, int y, const char *s, int bold);
void gr_texticon(int x, int y, gr_surface icon);
int gr_measure(const char *s);
void gr_font_size(int *x, int *y);
diff --git a/minui/resources.c b/minui/resources.c
index 065f4317e..72f39fbaa 100644
--- a/minui/resources.c
+++ b/minui/resources.c
@@ -93,22 +93,23 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
png_set_sig_bytes(png_ptr, sizeof(header));
png_read_info(png_ptr, info_ptr);
- size_t width = info_ptr->width;
- size_t height = info_ptr->height;
- size_t stride = 4 * width;
- size_t pixelSize = stride * height;
-
int color_type = info_ptr->color_type;
int bit_depth = info_ptr->bit_depth;
int channels = info_ptr->channels;
if (!(bit_depth == 8 &&
((channels == 3 && color_type == PNG_COLOR_TYPE_RGB) ||
(channels == 4 && color_type == PNG_COLOR_TYPE_RGBA) ||
- (channels == 1 && color_type == PNG_COLOR_TYPE_PALETTE)))) {
+ (channels == 1 && (color_type == PNG_COLOR_TYPE_PALETTE ||
+ color_type == PNG_COLOR_TYPE_GRAY))))) {
return -7;
goto exit;
}
+ size_t width = info_ptr->width;
+ size_t height = info_ptr->height;
+ size_t stride = (color_type == PNG_COLOR_TYPE_GRAY ? 1 : 4) * width;
+ size_t pixelSize = stride * height;
+
surface = malloc(sizeof(GGLSurface) + pixelSize);
if (surface == NULL) {
result = -8;
@@ -120,8 +121,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
surface->height = height;
surface->stride = width; /* Yes, pixels, not bytes */
surface->data = pData;
- surface->format = (channels == 3) ?
- GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888;
+ surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 :
+ ((color_type == PNG_COLOR_TYPE_PALETTE ? GGL_PIXEL_FORMAT_RGBA_8888 : GGL_PIXEL_FORMAT_L_8));
int alpha = 0;
if (color_type == PNG_COLOR_TYPE_PALETTE) {
@@ -131,6 +132,9 @@ int res_create_surface(const char* name, gr_surface* pSurface) {
png_set_tRNS_to_alpha(png_ptr);
alpha = 1;
}
+ if (color_type == PNG_COLOR_TYPE_GRAY) {
+ alpha = 1;
+ }
unsigned int y;
if (channels == 3 || (channels == 1 && !alpha)) {
diff --git a/minzip/Zip.c b/minzip/Zip.c
index c87f038c5..439e5d9cd 100644
--- a/minzip/Zip.c
+++ b/minzip/Zip.c
@@ -985,6 +985,7 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
unsigned int i;
bool seenMatch = false;
int ok = true;
+ int extractCount = 0;
for (i = 0; i < pArchive->numEntries; i++) {
ZipEntry *pEntry = pArchive->pEntries + i;
if (pEntry->fileNameLen < zipDirLen) {
@@ -1150,13 +1151,16 @@ bool mzExtractRecursive(const ZipArchive *pArchive,
break;
}
- LOGD("Extracted file \"%s\"\n", targetFile);
+ LOGV("Extracted file \"%s\"\n", targetFile);
+ ++extractCount;
}
}
if (callback != NULL) callback(targetFile, cookie);
}
+ LOGD("Extracted %d file(s)\n", extractCount);
+
free(helper.buf);
free(zpath);
diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk
index ef417fa19..f04355b5e 100644
--- a/mtdutils/Android.mk
+++ b/mtdutils/Android.mk
@@ -14,5 +14,5 @@ LOCAL_SRC_FILES := flash_image.c
LOCAL_MODULE := flash_image
LOCAL_MODULE_TAGS := eng
LOCAL_STATIC_LIBRARIES := libmtdutils
-LOCAL_SHARED_LIBRARIES := libcutils libc
+LOCAL_SHARED_LIBRARIES := libcutils liblog libc
include $(BUILD_EXECUTABLE)
diff --git a/recovery.cpp b/recovery.cpp
index 2541e54d8..c82844d25 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -15,11 +15,13 @@
*/
#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
#include <linux/input.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -27,7 +29,6 @@
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-#include <dirent.h>
#include "bootloader.h"
#include "common.h"
@@ -58,10 +59,11 @@ static const struct option OPTIONS[] = {
{ NULL, 0, NULL, 0 },
};
+#define LAST_LOG_FILE "/cache/recovery/last_log"
+
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 *LAST_LOG_FILE = "/cache/recovery/last_log";
static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install";
static const char *LOCALE_FILE = "/cache/recovery/last_locale";
static const char *CACHE_ROOT = "/cache";
@@ -265,6 +267,21 @@ copy_log_file(const char* source, const char* destination, int append) {
}
}
+// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max
+// Overwrites any existing last_log.$max.
+static void
+rotate_last_logs(int max) {
+ char oldfn[256];
+ char newfn[256];
+
+ int i;
+ for (i = max-1; i >= 0; --i) {
+ snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i);
+ snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1);
+ // ignore errors
+ rename(oldfn, newfn);
+ }
+}
// 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
@@ -710,7 +727,6 @@ prompt_and_wait(Device* device, int status) {
break;
case Device::WIPE_CACHE:
- ui->ShowText(false);
ui->Print("\n-- Wiping cache...\n");
erase_volume("/cache");
ui->Print("Cache wipe complete.\n");
@@ -808,6 +824,24 @@ load_locale_from_cache() {
}
}
+static RecoveryUI* gCurrentUI = NULL;
+
+void
+ui_print(const char* format, ...) {
+ char buffer[256];
+
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+
+ if (gCurrentUI != NULL) {
+ gCurrentUI->Print("%s", buffer);
+ } else {
+ fputs(buffer, stdout);
+ }
+}
+
int
main(int argc, char **argv) {
time_t start = time(NULL);
@@ -831,6 +865,8 @@ main(int argc, char **argv) {
printf("Starting recovery on %s", ctime(&start));
load_volume_table();
+ ensure_path_mounted(LAST_LOG_FILE);
+ rotate_last_logs(5);
get_args(&argc, &argv);
int previous_runs = 0;
@@ -863,6 +899,7 @@ main(int argc, char **argv) {
Device* device = make_device();
ui = device->GetUI();
+ gCurrentUI = ui;
ui->Init();
ui->SetLocale(locale);
@@ -916,7 +953,18 @@ main(int argc, char **argv) {
LOGE("Cache wipe (requested by package) failed.");
}
}
- if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n");
+ if (status != INSTALL_SUCCESS) {
+ ui->Print("Installation aborted.\n");
+
+ // If this is an eng or userdebug build, then automatically
+ // turn the text display on if the script fails so the error
+ // message is visible.
+ char buffer[PROPERTY_VALUE_MAX+1];
+ property_get("ro.build.fingerprint", buffer, "");
+ if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) {
+ ui->ShowText(true);
+ }
+ }
} else if (wipe_data) {
if (device->WipeData()) status = INSTALL_ERROR;
if (erase_volume("/data")) status = INSTALL_ERROR;
diff --git a/roots.cpp b/roots.cpp
index ca37cf149..09471225d 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -22,120 +22,48 @@
#include <unistd.h>
#include <ctype.h>
+#include <fs_mgr.h>
#include "mtdutils/mtdutils.h"
#include "mtdutils/mounts.h"
#include "roots.h"
#include "common.h"
#include "make_ext4fs.h"
-static int num_volumes = 0;
-static Volume* device_volumes = NULL;
+static struct fstab *fstab = NULL;
extern struct selabel_handle *sehandle;
-static int parse_options(char* options, Volume* volume) {
- char* option;
- while ((option = strtok(options, ","))) {
- options = NULL;
-
- if (strncmp(option, "length=", 7) == 0) {
- volume->length = strtoll(option+7, NULL, 10);
- } else {
- LOGE("bad option \"%s\"\n", option);
- return -1;
- }
- }
- return 0;
-}
-
-void load_volume_table() {
- int alloc = 2;
- device_volumes = (Volume*)malloc(alloc * sizeof(Volume));
-
- // Insert an entry for /tmp, which is the ramdisk and is always mounted.
- device_volumes[0].mount_point = "/tmp";
- device_volumes[0].fs_type = "ramdisk";
- device_volumes[0].device = NULL;
- device_volumes[0].device2 = NULL;
- device_volumes[0].length = 0;
- num_volumes = 1;
+void load_volume_table()
+{
+ int i;
+ int ret;
- FILE* fstab = fopen("/etc/recovery.fstab", "r");
- if (fstab == NULL) {
- LOGE("failed to open /etc/recovery.fstab (%s)\n", strerror(errno));
+ fstab = fs_mgr_read_fstab("/etc/recovery.fstab");
+ if (!fstab) {
+ LOGE("failed to read /etc/recovery.fstab\n");
return;
}
- char buffer[1024];
- int i;
- while (fgets(buffer, sizeof(buffer)-1, fstab)) {
- for (i = 0; buffer[i] && isspace(buffer[i]); ++i);
- if (buffer[i] == '\0' || buffer[i] == '#') continue;
-
- char* original = strdup(buffer);
-
- char* mount_point = strtok(buffer+i, " \t\n");
- char* fs_type = strtok(NULL, " \t\n");
- char* device = strtok(NULL, " \t\n");
- // lines may optionally have a second device, to use if
- // mounting the first one fails.
- char* options = NULL;
- char* device2 = strtok(NULL, " \t\n");
- if (device2) {
- if (device2[0] == '/') {
- options = strtok(NULL, " \t\n");
- } else {
- options = device2;
- device2 = NULL;
- }
- }
-
- if (mount_point && fs_type && device) {
- while (num_volumes >= alloc) {
- alloc *= 2;
- device_volumes = (Volume*)realloc(device_volumes, alloc*sizeof(Volume));
- }
- device_volumes[num_volumes].mount_point = strdup(mount_point);
- device_volumes[num_volumes].fs_type = strdup(fs_type);
- device_volumes[num_volumes].device = strdup(device);
- device_volumes[num_volumes].device2 =
- device2 ? strdup(device2) : NULL;
-
- device_volumes[num_volumes].length = 0;
- if (parse_options(options, device_volumes + num_volumes) != 0) {
- LOGE("skipping malformed recovery.fstab line: %s\n", original);
- } else {
- ++num_volumes;
- }
- } else {
- LOGE("skipping malformed recovery.fstab line: %s\n", original);
- }
- free(original);
+ ret = fs_mgr_add_entry(fstab, "/tmp", "ramdisk", "ramdisk", 0);
+ if (ret < 0 ) {
+ LOGE("failed to add /tmp entry to fstab\n");
+ fs_mgr_free_fstab(fstab);
+ fstab = NULL;
+ return;
}
- fclose(fstab);
-
printf("recovery filesystem table\n");
printf("=========================\n");
- for (i = 0; i < num_volumes; ++i) {
- Volume* v = &device_volumes[i];
- printf(" %d %s %s %s %s %lld\n", i, v->mount_point, v->fs_type,
- v->device, v->device2, v->length);
+ for (i = 0; i < fstab->num_entries; ++i) {
+ Volume* v = &fstab->recs[i];
+ printf(" %d %s %s %s %lld\n", i, v->mount_point, v->fs_type,
+ v->blk_device, v->length);
}
printf("\n");
}
Volume* volume_for_path(const char* path) {
- int i;
- for (i = 0; i < num_volumes; ++i) {
- Volume* v = device_volumes+i;
- int len = strlen(v->mount_point);
- if (strncmp(path, v->mount_point, len) == 0 &&
- (path[len] == '\0' || path[len] == '/')) {
- return v;
- }
- }
- return NULL;
+ return fs_mgr_get_entry_for_mount_point(fstab, path);
}
int ensure_path_mounted(const char* path) {
@@ -169,27 +97,19 @@ int ensure_path_mounted(const char* path) {
// mount an MTD partition as a YAFFS2 filesystem.
mtd_scan_partitions();
const MtdPartition* partition;
- partition = mtd_find_partition_by_name(v->device);
+ partition = mtd_find_partition_by_name(v->blk_device);
if (partition == NULL) {
LOGE("failed to find \"%s\" partition to mount at \"%s\"\n",
- v->device, v->mount_point);
+ v->blk_device, v->mount_point);
return -1;
}
return mtd_mount_partition(partition, v->mount_point, v->fs_type, 0);
} else if (strcmp(v->fs_type, "ext4") == 0 ||
strcmp(v->fs_type, "vfat") == 0) {
- result = mount(v->device, v->mount_point, v->fs_type,
+ result = mount(v->blk_device, v->mount_point, v->fs_type,
MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
if (result == 0) return 0;
- if (v->device2) {
- LOGW("failed to mount %s (%s); trying %s\n",
- v->device, strerror(errno), v->device2);
- result = mount(v->device2, v->mount_point, v->fs_type,
- MS_NOATIME | MS_NODEV | MS_NODIRATIME, "");
- if (result == 0) return 0;
- }
-
LOGE("failed to mount %s (%s)\n", v->mount_point, strerror(errno));
return -1;
}
@@ -249,31 +169,31 @@ int format_volume(const char* volume) {
if (strcmp(v->fs_type, "yaffs2") == 0 || strcmp(v->fs_type, "mtd") == 0) {
mtd_scan_partitions();
- const MtdPartition* partition = mtd_find_partition_by_name(v->device);
+ const MtdPartition* partition = mtd_find_partition_by_name(v->blk_device);
if (partition == NULL) {
- LOGE("format_volume: no MTD partition \"%s\"\n", v->device);
+ LOGE("format_volume: no MTD partition \"%s\"\n", v->blk_device);
return -1;
}
MtdWriteContext *write = mtd_write_partition(partition);
if (write == NULL) {
- LOGW("format_volume: can't open MTD \"%s\"\n", v->device);
+ LOGW("format_volume: can't open MTD \"%s\"\n", v->blk_device);
return -1;
} else if (mtd_erase_blocks(write, -1) == (off_t) -1) {
- LOGW("format_volume: can't erase MTD \"%s\"\n", v->device);
+ LOGW("format_volume: can't erase MTD \"%s\"\n", v->blk_device);
mtd_write_close(write);
return -1;
} else if (mtd_write_close(write)) {
- LOGW("format_volume: can't close MTD \"%s\"\n", v->device);
+ LOGW("format_volume: can't close MTD \"%s\"\n", v->blk_device);
return -1;
}
return 0;
}
if (strcmp(v->fs_type, "ext4") == 0) {
- int result = make_ext4fs(v->device, v->length, volume, sehandle);
+ int result = make_ext4fs(v->blk_device, v->length, volume, sehandle);
if (result != 0) {
- LOGE("format_volume: make_extf4fs failed on %s\n", v->device);
+ LOGE("format_volume: make_extf4fs failed on %s\n", v->blk_device);
return -1;
}
return 0;
diff --git a/screen_ui.cpp b/screen_ui.cpp
index e36fa3d8f..222de00ee 100644
--- a/screen_ui.cpp
+++ b/screen_ui.cpp
@@ -34,8 +34,8 @@
#include "screen_ui.h"
#include "ui.h"
-#define CHAR_WIDTH 10
-#define CHAR_HEIGHT 18
+static int char_width;
+static int char_height;
// There's only (at most) one of these objects, and global callbacks
// (for pthread_create, and the input event system) need to find it,
@@ -192,11 +192,9 @@ void ScreenRecoveryUI::draw_progress_locked()
}
}
-void ScreenRecoveryUI::draw_text_line(int row, const char* t) {
- if (t[0] != '\0') {
- gr_text(0, (row+1)*CHAR_HEIGHT-1, t);
- }
-}
+#define C_HEADER 247,0,6
+#define C_MENU 0,106,157
+#define C_LOG 249,194,0
// Redraw everything on the screen. Does not flip pages.
// Should only be called with updateMutex locked.
@@ -209,30 +207,46 @@ void ScreenRecoveryUI::draw_screen_locked()
gr_color(0, 0, 0, 160);
gr_fill(0, 0, gr_fb_width(), gr_fb_height());
+ int y = 0;
int i = 0;
if (show_menu) {
- gr_color(64, 96, 255, 255);
- gr_fill(0, (menu_top+menu_sel) * CHAR_HEIGHT,
- gr_fb_width(), (menu_top+menu_sel+1)*CHAR_HEIGHT+1);
+ gr_color(C_HEADER, 255);
for (; i < menu_top + menu_items; ++i) {
+ if (i == menu_top) gr_color(C_MENU, 255);
+
if (i == menu_top + menu_sel) {
+ // draw the highlight bar
+ gr_fill(0, y-2, gr_fb_width(), y+char_height+2);
+ // white text of selected item
gr_color(255, 255, 255, 255);
- draw_text_line(i, menu[i]);
- gr_color(64, 96, 255, 255);
+ if (menu[i][0]) gr_text(4, y, menu[i], 1);
+ gr_color(C_MENU, 255);
} else {
- draw_text_line(i, menu[i]);
+ if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top);
}
+ y += char_height+4;
}
- gr_fill(0, i*CHAR_HEIGHT+CHAR_HEIGHT/2-1,
- gr_fb_width(), i*CHAR_HEIGHT+CHAR_HEIGHT/2+1);
+ gr_color(C_MENU, 255);
+ y += 4;
+ gr_fill(0, y, gr_fb_width(), y+2);
+ y += 4;
++i;
}
- gr_color(255, 255, 0, 255);
-
- for (; i < text_rows; ++i) {
- draw_text_line(i, text[(i+text_top) % text_rows]);
+ gr_color(C_LOG, 255);
+
+ // display from the bottom up, until we hit the top of the
+ // screen, the bottom of the menu, or we've displayed the
+ // entire text buffer.
+ int ty;
+ int row = (text_top+text_rows-1) % text_rows;
+ for (int ty = gr_fb_height() - char_height, count = 0;
+ ty > y+2 && count < text_rows;
+ ty -= char_height, ++count) {
+ gr_text(4, ty, text[row], 0);
+ --row;
+ if (row < 0) row = text_rows-1;
}
}
}
@@ -327,12 +341,14 @@ void ScreenRecoveryUI::Init()
{
gr_init();
+ gr_font_size(&char_width, &char_height);
+
text_col = text_row = 0;
- text_rows = gr_fb_height() / CHAR_HEIGHT;
+ text_rows = gr_fb_height() / char_height;
if (text_rows > kMaxRows) text_rows = kMaxRows;
text_top = 1;
- text_cols = gr_fb_width() / CHAR_WIDTH;
+ text_cols = gr_fb_width() / char_width;
if (text_cols > kMaxCols - 1) text_cols = kMaxCols - 1;
LoadBitmap("icon_installing", &backgroundIcon[INSTALLING_UPDATE]);
diff --git a/screen_ui.h b/screen_ui.h
index 80051724b..fe0de46e8 100644
--- a/screen_ui.h
+++ b/screen_ui.h
@@ -76,7 +76,7 @@ class ScreenRecoveryUI : public RecoveryUI {
bool pagesIdentical;
static const int kMaxCols = 96;
- static const int kMaxRows = 32;
+ static const int kMaxRows = 96;
// Log text overlay, displayed when a magic key is pressed
char text[kMaxRows][kMaxCols];
@@ -100,7 +100,6 @@ class ScreenRecoveryUI : public RecoveryUI {
void draw_install_overlay_locked(int frame);
void draw_background_locked(Icon icon);
void draw_progress_locked();
- void draw_text_line(int row, const char* t);
void draw_screen_locked();
void update_screen_locked();
void update_progress_locked();
diff --git a/updater/Android.mk b/updater/Android.mk
index 4271371e9..67e98ecd4 100644
--- a/updater/Android.mk
+++ b/updater/Android.mk
@@ -31,7 +31,7 @@ LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDA
LOCAL_STATIC_LIBRARIES += libapplypatch libedify libmtdutils libminzip libz
LOCAL_STATIC_LIBRARIES += libmincrypt libbz
LOCAL_STATIC_LIBRARIES += libminelf
-LOCAL_STATIC_LIBRARIES += libcutils libstdc++ libc
+LOCAL_STATIC_LIBRARIES += libcutils liblog libstdc++ libc
LOCAL_STATIC_LIBRARIES += libselinux
LOCAL_C_INCLUDES += $(LOCAL_PATH)/..
diff --git a/verifier.cpp b/verifier.cpp
index 1c5a41d1b..5f4c981e5 100644
--- a/verifier.cpp
+++ b/verifier.cpp
@@ -179,9 +179,111 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey
LOGI("whole-file signature verified against key %d\n", i);
free(eocd);
return VERIFY_SUCCESS;
+ } else {
+ LOGI("failed to verify against key %d\n", i);
}
}
free(eocd);
LOGE("failed to verify whole-file signature\n");
return VERIFY_FAILURE;
}
+
+// Reads a file containing one or more public keys as produced by
+// DumpPublicKey: this is an RSAPublicKey struct as it would appear
+// as a C source literal, eg:
+//
+// "{64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
+//
+// For key versions newer than the original 2048-bit e=3 keys
+// supported by Android, the string is preceded by a version
+// identifier, eg:
+//
+// "v2 {64,0xc926ad21,{1795090719,...,-695002876},{-857949815,...,1175080310}}"
+//
+// (Note that the braces and commas in this example are actual
+// characters the parser expects to find in the file; the ellipses
+// indicate more numbers omitted from this example.)
+//
+// The file may contain multiple keys in this format, separated by
+// commas. The last key must not be followed by a comma.
+//
+// Returns NULL if the file failed to parse, or if it contain zero keys.
+RSAPublicKey*
+load_keys(const char* filename, int* numKeys) {
+ RSAPublicKey* out = NULL;
+ *numKeys = 0;
+
+ FILE* f = fopen(filename, "r");
+ if (f == NULL) {
+ LOGE("opening %s: %s\n", filename, strerror(errno));
+ goto exit;
+ }
+
+ {
+ int i;
+ bool done = false;
+ while (!done) {
+ ++*numKeys;
+ out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey));
+ RSAPublicKey* key = out + (*numKeys - 1);
+
+ char start_char;
+ if (fscanf(f, " %c", &start_char) != 1) goto exit;
+ if (start_char == '{') {
+ // a version 1 key has no version specifier.
+ key->exponent = 3;
+ } else if (start_char == 'v') {
+ int version;
+ if (fscanf(f, "%d {", &version) != 1) goto exit;
+ if (version == 2) {
+ key->exponent = 65537;
+ } else {
+ goto exit;
+ }
+ }
+
+ if (fscanf(f, " %i , 0x%x , { %u",
+ &(key->len), &(key->n0inv), &(key->n[0])) != 3) {
+ goto exit;
+ }
+ if (key->len != RSANUMWORDS) {
+ LOGE("key length (%d) does not match expected size\n", key->len);
+ goto exit;
+ }
+ for (i = 1; i < key->len; ++i) {
+ if (fscanf(f, " , %u", &(key->n[i])) != 1) goto exit;
+ }
+ if (fscanf(f, " } , { %u", &(key->rr[0])) != 1) goto exit;
+ for (i = 1; i < key->len; ++i) {
+ if (fscanf(f, " , %u", &(key->rr[i])) != 1) goto exit;
+ }
+ fscanf(f, " } } ");
+
+ // if the line ends in a comma, this file has more keys.
+ switch (fgetc(f)) {
+ case ',':
+ // more keys to come.
+ break;
+
+ case EOF:
+ done = true;
+ break;
+
+ default:
+ LOGE("unexpected character between keys\n");
+ goto exit;
+ }
+
+ LOGI("read key e=%d\n", key->exponent);
+ }
+ }
+
+ fclose(f);
+ return out;
+
+exit:
+ if (f) fclose(f);
+ free(out);
+ *numKeys = 0;
+ return NULL;
+}
diff --git a/verifier.h b/verifier.h
index 1bdfca6dd..e9ef3b722 100644
--- a/verifier.h
+++ b/verifier.h
@@ -24,6 +24,8 @@
*/
int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys);
+RSAPublicKey* load_keys(const char* filename, int* numKeys);
+
#define VERIFY_SUCCESS 0
#define VERIFY_FAILURE 1
diff --git a/verifier_test.cpp b/verifier_test.cpp
index 01d092680..2ef52a0f7 100644
--- a/verifier_test.cpp
+++ b/verifier_test.cpp
@@ -18,6 +18,7 @@
#include <stdlib.h>
#include <stdarg.h>
+#include "common.h"
#include "verifier.h"
#include "ui.h"
@@ -113,13 +114,10 @@ class FakeUI : public RecoveryUI {
bool IsTextVisible() { return false; }
bool WasTextEverVisible() { return false; }
void Print(const char* fmt, ...) {
- char buf[256];
va_list ap;
va_start(ap, fmt);
- vsnprintf(buf, 256, fmt, ap);
+ vfprintf(stderr, fmt, ap);
va_end(ap);
-
- fputs(buf, stderr);
}
void StartMenu(const char* const * headers, const char* const * items,
@@ -128,22 +126,35 @@ class FakeUI : public RecoveryUI {
void EndMenu() { }
};
+void
+ui_print(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stdout, format, ap);
+ va_end(ap);
+}
+
int main(int argc, char **argv) {
- if (argc != 2 && argc != 3) {
- fprintf(stderr, "Usage: %s [-f4] <package>\n", argv[0]);
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, "Usage: %s [-f4 | -file <keys>] <package>\n", argv[0]);
return 2;
}
RSAPublicKey* key = &test_key;
+ int num_keys = 1;
++argv;
if (strcmp(argv[0], "-f4") == 0) {
++argv;
key = &test_f4_key;
+ } else if (strcmp(argv[0], "-file") == 0) {
+ ++argv;
+ key = load_keys(argv[0], &num_keys);
+ ++argv;
}
ui = new FakeUI();
- int result = verify_file(*argv, key, 1);
+ int result = verify_file(*argv, key, num_keys);
if (result == VERIFY_SUCCESS) {
printf("SUCCESS\n");
return 0;