diff options
-rw-r--r-- | Android.mk | 3 | ||||
-rw-r--r-- | CleanSpec.mk | 1 | ||||
-rw-r--r-- | applypatch/applypatch.c | 27 | ||||
-rw-r--r-- | bootloader.cpp | 43 | ||||
-rw-r--r-- | common.h | 25 | ||||
-rw-r--r-- | fonts/12x22.png | bin | 0 -> 14431 bytes | |||
-rw-r--r-- | fonts/18x32.png | bin | 0 -> 24437 bytes | |||
-rw-r--r-- | fonts/OFL.txt | 93 | ||||
-rw-r--r-- | fonts/README | 6 | ||||
-rw-r--r-- | install.cpp | 100 | ||||
-rw-r--r-- | minui/graphics.c | 65 | ||||
-rw-r--r-- | minui/minui.h | 2 | ||||
-rw-r--r-- | minui/resources.c | 20 | ||||
-rw-r--r-- | minzip/Zip.c | 6 | ||||
-rw-r--r-- | mtdutils/Android.mk | 2 | ||||
-rw-r--r-- | recovery.cpp | 56 | ||||
-rw-r--r-- | roots.cpp | 140 | ||||
-rw-r--r-- | screen_ui.cpp | 58 | ||||
-rw-r--r-- | screen_ui.h | 3 | ||||
-rw-r--r-- | updater/Android.mk | 2 | ||||
-rw-r--r-- | verifier.cpp | 102 | ||||
-rw-r--r-- | verifier.h | 2 | ||||
-rw-r--r-- | verifier_test.cpp | 25 |
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; @@ -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 Binary files differnew file mode 100644 index 000000000..ae826bebe --- /dev/null +++ b/fonts/12x22.png diff --git a/fonts/18x32.png b/fonts/18x32.png Binary files differnew file mode 100644 index 000000000..d95408a93 --- /dev/null +++ b/fonts/18x32.png 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; @@ -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; |