diff options
40 files changed, 411 insertions, 508 deletions
diff --git a/Android.mk b/Android.mk index 27ffec70f..508eb4c64 100644 --- a/Android.mk +++ b/Android.mk @@ -1,5 +1,4 @@ ifneq ($(TARGET_SIMULATOR),true) -ifeq ($(TARGET_ARCH),arm) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -12,8 +11,7 @@ LOCAL_SRC_FILES := \ install.c \ roots.c \ ui.c \ - verifier.c \ - encryptedfs_provisioning.c + verifier.c LOCAL_MODULE := recovery @@ -77,6 +75,4 @@ include $(commands_recovery_local_path)/updater/Android.mk include $(commands_recovery_local_path)/applypatch/Android.mk commands_recovery_local_path := -endif # TARGET_ARCH == arm endif # !TARGET_SIMULATOR - diff --git a/applypatch/Android.mk b/applypatch/Android.mk index eff1d77b3..2848b517e 100644 --- a/applypatch/Android.mk +++ b/applypatch/Android.mk @@ -14,7 +14,6 @@ ifneq ($(TARGET_SIMULATOR),true) -ifeq ($(TARGET_ARCH),arm) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -59,5 +58,4 @@ LOCAL_STATIC_LIBRARIES += libz libbz include $(BUILD_HOST_EXECUTABLE) -endif # TARGET_ARCH == arm endif # !TARGET_SIMULATOR diff --git a/bootloader.c b/bootloader.c index b690c5582..709656602 100644 --- a/bootloader.c +++ b/bootloader.c @@ -22,6 +22,8 @@ #include <errno.h> #include <stdio.h> #include <string.h> +#include <sys/stat.h> +#include <unistd.h> static int get_bootloader_message_mtd(struct bootloader_message *out, const Volume* v); static int set_bootloader_message_mtd(const struct bootloader_message *in, const Volume* v); @@ -132,8 +134,26 @@ static int set_bootloader_message_mtd(const struct bootloader_message *in, // for misc partitions on block devices // ------------------------------------ +static void wait_for_device(const char* fn) { + int tries = 0; + int ret; + struct stat buf; + do { + ++tries; + ret = stat(fn, &buf); + if (ret) { + printf("stat %s try %d: %s\n", fn, tries, strerror(errno)); + sleep(1); + } + } while (ret && tries < 10); + if (ret) { + printf("failed to stat %s\n", 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"); if (f == NULL) { LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); @@ -155,6 +175,7 @@ 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"); if (f == NULL) { LOGE("Can't open %s\n(%s)\n", v->device, strerror(errno)); @@ -107,4 +107,26 @@ typedef struct { // (that much). } Volume; +typedef struct { + // number of frames in indeterminate progress bar animation + int indeterminate_frames; + + // number of frames per second to try to maintain when animating + int update_fps; + + // number of frames in installing animation. may be zero for a + // static installation icon. + int installing_frames; + + // the install icon is animated by drawing images containing the + // changing part over the base icon. These specify the + // coordinates of the upper-left corner. + int install_overlay_offset_x; + int install_overlay_offset_y; + +} UIParameters; + +// fopen a file, mounting volumes and making parent dirs as necessary. +FILE* fopen_path(const char *path, const char *mode); + #endif // RECOVERY_COMMON_H diff --git a/default_recovery_ui.c b/default_recovery_ui.c index bcba88826..7c4017e7e 100644 --- a/default_recovery_ui.c +++ b/default_recovery_ui.c @@ -29,6 +29,9 @@ char* MENU_ITEMS[] = { "reboot system now", "wipe cache partition", NULL }; +void device_ui_init(UIParameters* ui_parameters) { +} + int device_recovery_start() { return 0; } diff --git a/encryptedfs_provisioning.c b/encryptedfs_provisioning.c deleted file mode 100644 index 601c817de..000000000 --- a/encryptedfs_provisioning.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/mount.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "encryptedfs_provisioning.h" -#include "cutils/misc.h" -#include "cutils/properties.h" -#include "common.h" -#include "mtdutils/mtdutils.h" -#include "mtdutils/mounts.h" -#include "roots.h" - -const char* encrypted_fs_enabled_property = "persist.security.secfs.enabled"; -const char* encrypted_fs_property_dir = "/data/property/"; -const char* encrypted_fs_system_dir = "/data/system/"; -const char* encrypted_fs_key_file_name = "/data/fs_key.dat"; -const char* encrypted_fs_salt_file_name = "/data/hash_salt.dat"; -const char* encrypted_fs_hash_file_src_name = "/data/system/password.key"; -const char* encrypted_fs_hash_file_dst_name = "/data/hash.dat"; -const char* encrypted_fs_entropy_file_src_name = "/data/system/entropy.dat"; -const char* encrypted_fs_entropy_file_dst_name = "/data/ported_entropy.dat"; - -void get_property_file_name(char *buffer, const char *property_name) { - sprintf(buffer, "%s%s", encrypted_fs_property_dir, property_name); -} - -int get_binary_file_contents(char *buffer, int buf_size, const char *file_name, int *out_size) { - FILE *in_file; - int read_bytes; - - in_file = fopen(file_name, "r"); - if (in_file == NULL) { - LOGE("Secure FS: error accessing key file."); - return ENCRYPTED_FS_ERROR; - } - - read_bytes = fread(buffer, 1, buf_size, in_file); - if (out_size == NULL) { - if (read_bytes != buf_size) { - // Error or unexpected data - fclose(in_file); - LOGE("Secure FS: error reading conmplete key."); - return ENCRYPTED_FS_ERROR; - } - } else { - *out_size = read_bytes; - } - fclose(in_file); - return ENCRYPTED_FS_OK; -} - -int set_binary_file_contents(char *buffer, int buf_size, const char *file_name) { - FILE *out_file; - int write_bytes; - - out_file = fopen(file_name, "w"); - if (out_file == NULL) { - LOGE("Secure FS: error setting up key file."); - return ENCRYPTED_FS_ERROR; - } - - write_bytes = fwrite(buffer, 1, buf_size, out_file); - if (write_bytes != buf_size) { - // Error or unexpected data - fclose(out_file); - LOGE("Secure FS: error reading conmplete key."); - return ENCRYPTED_FS_ERROR; - } - - fclose(out_file); - return ENCRYPTED_FS_OK; -} - -int get_text_file_contents(char *buffer, int buf_size, char *file_name) { - FILE *in_file; - char *read_data; - - in_file = fopen(file_name, "r"); - if (in_file == NULL) { - LOGE("Secure FS: error accessing properties."); - return ENCRYPTED_FS_ERROR; - } - - read_data = fgets(buffer, buf_size, in_file); - if (read_data == NULL) { - // Error or unexpected data - fclose(in_file); - LOGE("Secure FS: error accessing properties."); - return ENCRYPTED_FS_ERROR; - } - - fclose(in_file); - return ENCRYPTED_FS_OK; -} - -int set_text_file_contents(char *buffer, char *file_name) { - FILE *out_file; - int result; - - out_file = fopen(file_name, "w"); - if (out_file == NULL) { - LOGE("Secure FS: error setting up properties."); - return ENCRYPTED_FS_ERROR; - } - - result = fputs(buffer, out_file); - if (result != 0) { - // Error or unexpected data - fclose(out_file); - LOGE("Secure FS: error setting up properties."); - return ENCRYPTED_FS_ERROR; - } - - fflush(out_file); - fclose(out_file); - return ENCRYPTED_FS_OK; -} - -int read_encrypted_fs_boolean_property(const char *prop_name, int *value) { - char prop_file_name[PROPERTY_KEY_MAX + 32]; - char prop_value[PROPERTY_VALUE_MAX]; - int result; - - get_property_file_name(prop_file_name, prop_name); - result = get_text_file_contents(prop_value, PROPERTY_VALUE_MAX, prop_file_name); - - if (result < 0) { - return result; - } - - if (strncmp(prop_value, "1", 1) == 0) { - *value = 1; - } else if (strncmp(prop_value, "0", 1) == 0) { - *value = 0; - } else { - LOGE("Secure FS: error accessing properties."); - return ENCRYPTED_FS_ERROR; - } - - return ENCRYPTED_FS_OK; -} - -int write_encrypted_fs_boolean_property(const char *prop_name, int value) { - char prop_file_name[PROPERTY_KEY_MAX + 32]; - char prop_value[PROPERTY_VALUE_MAX]; - int result; - - get_property_file_name(prop_file_name, prop_name); - - // Create the directory if needed - mkdir(encrypted_fs_property_dir, 0755); - if (value == 1) { - result = set_text_file_contents("1", prop_file_name); - } else if (value == 0) { - result = set_text_file_contents("0", prop_file_name); - } else { - return ENCRYPTED_FS_ERROR; - } - if (result < 0) { - return result; - } - - return ENCRYPTED_FS_OK; -} - -int read_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data) { - int result; - int value; - result = ensure_path_mounted("/data"); - if (result != 0) { - LOGE("Secure FS: error mounting userdata partition."); - return ENCRYPTED_FS_ERROR; - } - - // Read the pre-generated encrypted FS key, password hash and salt. - result = get_binary_file_contents(encrypted_fs_data->key, ENCRYPTED_FS_KEY_SIZE, - encrypted_fs_key_file_name, NULL); - if (result != 0) { - LOGE("Secure FS: error reading generated file system key."); - return ENCRYPTED_FS_ERROR; - } - - result = get_binary_file_contents(encrypted_fs_data->salt, ENCRYPTED_FS_SALT_SIZE, - encrypted_fs_salt_file_name, &(encrypted_fs_data->salt_length)); - if (result != 0) { - LOGE("Secure FS: error reading file system salt."); - return ENCRYPTED_FS_ERROR; - } - - result = get_binary_file_contents(encrypted_fs_data->hash, ENCRYPTED_FS_MAX_HASH_SIZE, - encrypted_fs_hash_file_src_name, &(encrypted_fs_data->hash_length)); - if (result != 0) { - LOGE("Secure FS: error reading password hash."); - return ENCRYPTED_FS_ERROR; - } - - result = get_binary_file_contents(encrypted_fs_data->entropy, ENTROPY_MAX_SIZE, - encrypted_fs_entropy_file_src_name, &(encrypted_fs_data->entropy_length)); - if (result != 0) { - LOGE("Secure FS: error reading ported entropy."); - return ENCRYPTED_FS_ERROR; - } - - result = ensure_path_unmounted("/data"); - if (result != 0) { - LOGE("Secure FS: error unmounting data partition."); - return ENCRYPTED_FS_ERROR; - } - - return ENCRYPTED_FS_OK; -} - -int restore_encrypted_fs_info(encrypted_fs_info *encrypted_fs_data) { - int result; - result = ensure_path_mounted("/data"); - if (result != 0) { - LOGE("Secure FS: error mounting userdata partition."); - return ENCRYPTED_FS_ERROR; - } - - // Write the pre-generated secure FS key, password hash and salt. - result = set_binary_file_contents(encrypted_fs_data->key, ENCRYPTED_FS_KEY_SIZE, - encrypted_fs_key_file_name); - if (result != 0) { - LOGE("Secure FS: error writing generated file system key."); - return ENCRYPTED_FS_ERROR; - } - - result = set_binary_file_contents(encrypted_fs_data->salt, encrypted_fs_data->salt_length, - encrypted_fs_salt_file_name); - if (result != 0) { - LOGE("Secure FS: error writing file system salt."); - return ENCRYPTED_FS_ERROR; - } - - result = set_binary_file_contents(encrypted_fs_data->hash, encrypted_fs_data->hash_length, - encrypted_fs_hash_file_dst_name); - if (result != 0) { - LOGE("Secure FS: error writing password hash."); - return ENCRYPTED_FS_ERROR; - } - - result = set_binary_file_contents(encrypted_fs_data->entropy, encrypted_fs_data->entropy_length, - encrypted_fs_entropy_file_dst_name); - if (result != 0) { - LOGE("Secure FS: error writing ported entropy."); - return ENCRYPTED_FS_ERROR; - } - - // Set the secure FS properties to their respective values - result = write_encrypted_fs_boolean_property(encrypted_fs_enabled_property, encrypted_fs_data->mode); - if (result != 0) { - return result; - } - - result = ensure_path_unmounted("/data"); - if (result != 0) { - LOGE("Secure FS: error unmounting data partition."); - return ENCRYPTED_FS_ERROR; - } - - return ENCRYPTED_FS_OK; -} diff --git a/encryptedfs_provisioning.h b/encryptedfs_provisioning.h deleted file mode 100644 index 284605d20..000000000 --- a/encryptedfs_provisioning.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdio.h> - -#ifndef __ENCRYPTEDFS_PROVISIONING_H__ -#define __ENCRYPTEDFS_PROVISIONING_H__ - -#define MODE_ENCRYPTED_FS_DISABLED 0 -#define MODE_ENCRYPTED_FS_ENABLED 1 - -#define ENCRYPTED_FS_OK 0 -#define ENCRYPTED_FS_ERROR (-1) - -#define ENCRYPTED_FS_KEY_SIZE 16 -#define ENCRYPTED_FS_SALT_SIZE 16 -#define ENCRYPTED_FS_MAX_HASH_SIZE 128 -#define ENTROPY_MAX_SIZE 4096 - -struct encrypted_fs_info { - int mode; - char key[ENCRYPTED_FS_KEY_SIZE]; - char salt[ENCRYPTED_FS_SALT_SIZE]; - int salt_length; - char hash[ENCRYPTED_FS_MAX_HASH_SIZE]; - int hash_length; - char entropy[ENTROPY_MAX_SIZE]; - int entropy_length; -}; - -typedef struct encrypted_fs_info encrypted_fs_info; - -int read_encrypted_fs_info(encrypted_fs_info *secure_fs_data); - -int restore_encrypted_fs_info(encrypted_fs_info *secure_data); - -#endif /* __ENCRYPTEDFS_PROVISIONING_H__ */ - @@ -36,6 +36,8 @@ #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" #define PUBLIC_KEYS_FILE "/res/keys" +static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; + // If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip) { @@ -233,8 +235,8 @@ exit: return NULL; } -int -install_package(const char *path) +static int +really_install_package(const char *path) { ui_set_background(BACKGROUND_ICON_INSTALLING); ui_print("Finding update package...\n"); @@ -285,3 +287,23 @@ install_package(const char *path) ui_print("Installing update...\n"); return try_update_binary(path, &zip); } + +int +install_package(const char* path) +{ + FILE* install_log = fopen_path(LAST_INSTALL_FILE, "w"); + if (install_log) { + fputs(path, install_log); + fputc('\n', install_log); + } else { + LOGE("failed to open last_install: %s\n", strerror(errno)); + } + int result = really_install_package(path); + if (install_log) { + fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); + fputc('\n', install_log); + fclose(install_log); + chmod(LAST_INSTALL_FILE, 0644); + } + return result; +} diff --git a/make-overlay.py b/make-overlay.py new file mode 100644 index 000000000..7f931b373 --- /dev/null +++ b/make-overlay.py @@ -0,0 +1,102 @@ +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Script to take a set of frames (PNG files) for a recovery +"installing" icon animation and turn it into a base image plus a set +of overlays, as needed by the recovery UI code. Run with the names of +all the input frames on the command line, in order.""" + +import sys +try: + import Image +except ImportError: + print "This script requires the Python Imaging Library to be installed." + sys.exit(1) + +# Find the smallest box that contains all the pixels which change +# between images. + +print "reading", sys.argv[1] +base = Image.open(sys.argv[1]) + +minmini = base.size[0]-1 +maxmaxi = 0 +minminj = base.size[1]-1 +maxmaxj = 0 + +for top_name in sys.argv[2:]: + print "reading", top_name + top = Image.open(top_name) + + assert base.size == top.size + + mini = base.size[0]-1 + maxi = 0 + minj = base.size[1]-1 + maxj = 0 + + h, w = base.size + for j in range(w): + for i in range(h): + b = base.getpixel((i,j)) + t = top.getpixel((i,j)) + if b != t: + if i < mini: mini = i + if i > maxi: maxi = i + if j < minj: minj = j + if j > maxj: maxj = j + + minmini = min(minmini, mini) + maxmaxi = max(maxmaxi, maxi) + minminj = min(minminj, minj) + maxmaxj = max(maxmaxj, maxj) + +w = maxmaxi - minmini + 1 +h = maxmaxj - minminj + 1 + +# Now write out an image containing just that box, for each frame. + +for num, top_name in enumerate(sys.argv[1:]): + top = Image.open(top_name) + + out = Image.new("RGB", (w, h)) + for i in range(w): + for j in range(h): + t = top.getpixel((i+minmini, j+minminj)) + out.putpixel((i, j), t) + + fn = "icon_installing_overlay%02d.png" % (num+1,) + out.save(fn) + print "saved", fn + +# Write out the base icon, which is the first frame with that box +# blacked out (just to make the file smaller, since it's always +# displayed with one of the overlays on top of it). + +for i in range(w): + for j in range(h): + base.putpixel((i+minmini, j+minminj), (0, 0, 0)) +fn = "icon_installing.png" +base.save(fn) +print "saved", fn + +# The device_ui_init() function needs to tell the recovery UI the +# position of the overlay box. + +print +print "add this to your device_ui_init() function:" +print "-" * 40 +print " ui_parameters->install_overlay_offset_x = %d;" % (minmini,) +print " ui_parameters->install_overlay_offset_y = %d;" % (minminj,) +print "-" * 40 diff --git a/minui/resources.c b/minui/resources.c index 3d2c727fb..b437a87cb 100644 --- a/minui/resources.c +++ b/minui/resources.c @@ -49,6 +49,8 @@ int res_create_surface(const char* name, gr_surface* pSurface) { png_structp png_ptr = NULL; png_infop info_ptr = NULL; + *pSurface = NULL; + snprintf(resPath, sizeof(resPath)-1, "/res/images/%s.png", name); resPath[sizeof(resPath)-1] = '\0'; FILE* fp = fopen(resPath, "rb"); @@ -119,12 +121,17 @@ int res_create_surface(const char* name, gr_surface* pSurface) { surface->format = (channels == 3) ? GGL_PIXEL_FORMAT_RGBX_8888 : GGL_PIXEL_FORMAT_RGBA_8888; + int alpha = 0; if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_ptr); + png_set_palette_to_rgb(png_ptr); + } + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_ptr); + alpha = 1; } int y; - if (channels == 3) { + if (channels == 3 || (channels == 1 && !alpha)) { for (y = 0; y < height; ++y) { unsigned char* pRow = pData + y * stride; png_read_row(png_ptr, pRow, NULL); diff --git a/mtdutils/Android.mk b/mtdutils/Android.mk index 57ab579b2..416653698 100644 --- a/mtdutils/Android.mk +++ b/mtdutils/Android.mk @@ -1,5 +1,4 @@ ifneq ($(TARGET_SIMULATOR),true) -ifeq ($(TARGET_ARCH),arm) LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) @@ -20,5 +19,4 @@ LOCAL_STATIC_LIBRARIES := libmtdutils LOCAL_SHARED_LIBRARIES := libcutils libc include $(BUILD_EXECUTABLE) -endif # TARGET_ARCH == arm endif # !TARGET_SIMULATOR diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index 198f4989d..e4d2a6064 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c @@ -269,8 +269,8 @@ MtdReadContext *mtd_read_partition(const MtdPartition *partition) sprintf(mtddevname, "/dev/mtd/mtd%d", partition->device_index); ctx->fd = open(mtddevname, O_RDONLY); if (ctx->fd < 0) { - free(ctx); free(ctx->buffer); + free(ctx); return NULL; } diff --git a/recovery.c b/recovery.c index c81a13c37..3a412d5c5 100644 --- a/recovery.c +++ b/recovery.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/reboot.h> #include <sys/stat.h> #include <sys/types.h> #include <time.h> @@ -33,19 +32,18 @@ #include "bootloader.h" #include "common.h" #include "cutils/properties.h" +#include "cutils/android_reboot.h" #include "install.h" #include "minui/minui.h" #include "minzip/DirUtil.h" #include "roots.h" #include "recovery_ui.h" -#include "encryptedfs_provisioning.h" static const struct option OPTIONS[] = { { "send_intent", required_argument, NULL, 's' }, { "update_package", required_argument, NULL, 'u' }, { "wipe_data", no_argument, NULL, 'w' }, { "wipe_cache", no_argument, NULL, 'c' }, - { "set_encrypted_filesystems", required_argument, NULL, 'e' }, { "show_text", no_argument, NULL, 't' }, { NULL, 0, NULL, 0 }, }; @@ -58,6 +56,8 @@ static const char *SDCARD_ROOT = "/sdcard"; static const char *TEMPORARY_LOG_FILE = "/tmp/recovery.log"; static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; +extern UIParameters ui_parameters; // from ui.c + /* * The recovery tool communicates with the main system through /cache files. * /cache/recovery/command - INPUT - command line for tool, one arg per line @@ -114,33 +114,13 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; * 8g. finish_recovery() erases BCB * -- after this, rebooting will (try to) restart the main system -- * 9. main() calls reboot() to boot main system - * - * SECURE FILE SYSTEMS ENABLE/DISABLE - * 1. user selects "enable encrypted file systems" - * 2. main system writes "--set_encrypted_filesystems=on|off" to - * /cache/recovery/command - * 3. main system reboots into recovery - * 4. get_args() writes BCB with "boot-recovery" and - * "--set_encrypted_filesystems=on|off" - * -- after this, rebooting will restart the transition -- - * 5. read_encrypted_fs_info() retrieves encrypted file systems settings from /data - * Settings include: property to specify the Encrypted FS istatus and - * FS encryption key if enabled (not yet implemented) - * 6. erase_volume() reformats /data - * 7. erase_volume() reformats /cache - * 8. restore_encrypted_fs_info() writes required encrypted file systems settings to /data - * Settings include: property to specify the Encrypted FS status and - * FS encryption key if enabled (not yet implemented) - * 9. finish_recovery() erases BCB - * -- after this, rebooting will restart the main system -- - * 10. main() calls reboot() to boot main system */ static const int MAX_ARG_LENGTH = 4096; static const int MAX_ARGS = 100; // open a given path, mounting partitions as necessary -static FILE* +FILE* fopen_path(const char *path, const char *mode) { if (ensure_path_mounted(path) != 0) { LOGE("Can't mount %s\n", path); @@ -710,6 +690,7 @@ main(int argc, char **argv) { freopen(TEMPORARY_LOG_FILE, "a", stderr); setbuf(stderr, NULL); printf("Starting recovery on %s", ctime(&start)); + device_ui_init(&ui_parameters); ui_init(); ui_set_background(BACKGROUND_ICON_INSTALLING); load_volume_table(); @@ -718,10 +699,7 @@ main(int argc, char **argv) { int previous_runs = 0; const char *send_intent = NULL; const char *update_package = NULL; - const char *encrypted_fs_mode = NULL; int wipe_data = 0, wipe_cache = 0; - int toggle_secure_fs = 0; - encrypted_fs_info encrypted_fs_data; int arg; while ((arg = getopt_long(argc, argv, "", OPTIONS, NULL)) != -1) { @@ -731,7 +709,6 @@ main(int argc, char **argv) { case 'u': update_package = optarg; break; case 'w': wipe_data = wipe_cache = 1; break; case 'c': wipe_cache = 1; break; - case 'e': encrypted_fs_mode = optarg; toggle_secure_fs = 1; break; case 't': ui_show_text(1); break; case '?': LOGE("Invalid command argument\n"); @@ -768,43 +745,7 @@ main(int argc, char **argv) { int status = INSTALL_SUCCESS; - if (toggle_secure_fs) { - if (strcmp(encrypted_fs_mode,"on") == 0) { - encrypted_fs_data.mode = MODE_ENCRYPTED_FS_ENABLED; - ui_print("Enabling Encrypted FS.\n"); - } else if (strcmp(encrypted_fs_mode,"off") == 0) { - encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED; - ui_print("Disabling Encrypted FS.\n"); - } else { - ui_print("Error: invalid Encrypted FS setting.\n"); - status = INSTALL_ERROR; - } - - // Recovery strategy: if the data partition is damaged, disable encrypted file systems. - // This preventsthe device recycling endlessly in recovery mode. - if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) && - (read_encrypted_fs_info(&encrypted_fs_data))) { - ui_print("Encrypted FS change aborted, resetting to disabled state.\n"); - encrypted_fs_data.mode = MODE_ENCRYPTED_FS_DISABLED; - } - - if (status != INSTALL_ERROR) { - if (erase_volume("/data")) { - ui_print("Data wipe failed.\n"); - status = INSTALL_ERROR; - } else if (erase_volume("/cache")) { - ui_print("Cache wipe failed.\n"); - status = INSTALL_ERROR; - } else if ((encrypted_fs_data.mode == MODE_ENCRYPTED_FS_ENABLED) && - (restore_encrypted_fs_info(&encrypted_fs_data))) { - ui_print("Encrypted FS change aborted.\n"); - status = INSTALL_ERROR; - } else { - ui_print("Successfully updated Encrypted FS.\n"); - status = INSTALL_SUCCESS; - } - } - } else if (update_package != NULL) { + if (update_package != NULL) { status = install_package(update_package); if (status != INSTALL_SUCCESS) ui_print("Installation aborted.\n"); } else if (wipe_data) { @@ -827,7 +768,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui_print("Rebooting...\n"); - sync(); - reboot(RB_AUTOBOOT); + android_reboot(ANDROID_RB_RESTART, 0, 0); return EXIT_SUCCESS; } diff --git a/recovery_ui.h b/recovery_ui.h index 77ce7f93d..e56a24b29 100644 --- a/recovery_ui.h +++ b/recovery_ui.h @@ -17,6 +17,12 @@ #ifndef _RECOVERY_UI_H #define _RECOVERY_UI_H +#include "common.h" + +// Called before UI library is initialized. Can change things like +// how many frames are included in various animations, etc. +extern void device_ui_init(UIParameters* ui_parameters); + // Called when recovery starts up. Returns 0. extern int device_recovery_start(); diff --git a/res/images/icon_error.png b/res/images/icon_error.png Binary files differindex 90c8d878a..446c3fb19 100755..100644 --- a/res/images/icon_error.png +++ b/res/images/icon_error.png diff --git a/res/images/icon_installing.png b/res/images/icon_installing.png Binary files differindex d428f57d1..7e42628e7 100755..100644 --- a/res/images/icon_installing.png +++ b/res/images/icon_installing.png diff --git a/res/images/icon_installing_overlay01.png b/res/images/icon_installing_overlay01.png Binary files differnew file mode 100644 index 000000000..2c4c89a8b --- /dev/null +++ b/res/images/icon_installing_overlay01.png diff --git a/res/images/icon_installing_overlay02.png b/res/images/icon_installing_overlay02.png Binary files differnew file mode 100644 index 000000000..b63552bca --- /dev/null +++ b/res/images/icon_installing_overlay02.png diff --git a/res/images/icon_installing_overlay03.png b/res/images/icon_installing_overlay03.png Binary files differnew file mode 100644 index 000000000..6acb5ef63 --- /dev/null +++ b/res/images/icon_installing_overlay03.png diff --git a/res/images/icon_installing_overlay04.png b/res/images/icon_installing_overlay04.png Binary files differnew file mode 100644 index 000000000..0d4608aa4 --- /dev/null +++ b/res/images/icon_installing_overlay04.png diff --git a/res/images/icon_installing_overlay05.png b/res/images/icon_installing_overlay05.png Binary files differnew file mode 100644 index 000000000..4bfacb269 --- /dev/null +++ b/res/images/icon_installing_overlay05.png diff --git a/res/images/icon_installing_overlay06.png b/res/images/icon_installing_overlay06.png Binary files differnew file mode 100644 index 000000000..5fd252862 --- /dev/null +++ b/res/images/icon_installing_overlay06.png diff --git a/res/images/icon_installing_overlay07.png b/res/images/icon_installing_overlay07.png Binary files differnew file mode 100644 index 000000000..350b3814d --- /dev/null +++ b/res/images/icon_installing_overlay07.png diff --git a/res/images/indeterminate01.png b/res/images/indeterminate01.png Binary files differnew file mode 100644 index 000000000..84f04b0d2 --- /dev/null +++ b/res/images/indeterminate01.png diff --git a/res/images/indeterminate02.png b/res/images/indeterminate02.png Binary files differnew file mode 100644 index 000000000..21d012168 --- /dev/null +++ b/res/images/indeterminate02.png diff --git a/res/images/indeterminate03.png b/res/images/indeterminate03.png Binary files differnew file mode 100644 index 000000000..8a190a8c6 --- /dev/null +++ b/res/images/indeterminate03.png diff --git a/res/images/indeterminate04.png b/res/images/indeterminate04.png Binary files differnew file mode 100644 index 000000000..baf8d63e4 --- /dev/null +++ b/res/images/indeterminate04.png diff --git a/res/images/indeterminate05.png b/res/images/indeterminate05.png Binary files differnew file mode 100644 index 000000000..5653c7b06 --- /dev/null +++ b/res/images/indeterminate05.png diff --git a/res/images/indeterminate06.png b/res/images/indeterminate06.png Binary files differnew file mode 100644 index 000000000..858de85a5 --- /dev/null +++ b/res/images/indeterminate06.png diff --git a/res/images/indeterminate1.png b/res/images/indeterminate1.png Binary files differdeleted file mode 100644 index 90cb9fba9..000000000 --- a/res/images/indeterminate1.png +++ /dev/null diff --git a/res/images/indeterminate2.png b/res/images/indeterminate2.png Binary files differdeleted file mode 100644 index f7fb28989..000000000 --- a/res/images/indeterminate2.png +++ /dev/null diff --git a/res/images/indeterminate3.png b/res/images/indeterminate3.png Binary files differdeleted file mode 100644 index ba10dfa53..000000000 --- a/res/images/indeterminate3.png +++ /dev/null diff --git a/res/images/indeterminate4.png b/res/images/indeterminate4.png Binary files differdeleted file mode 100644 index ad5d9a542..000000000 --- a/res/images/indeterminate4.png +++ /dev/null diff --git a/res/images/indeterminate5.png b/res/images/indeterminate5.png Binary files differdeleted file mode 100644 index 8c19c8d57..000000000 --- a/res/images/indeterminate5.png +++ /dev/null diff --git a/res/images/indeterminate6.png b/res/images/indeterminate6.png Binary files differdeleted file mode 100644 index c0c66386a..000000000 --- a/res/images/indeterminate6.png +++ /dev/null diff --git a/res/images/progress_empty.png b/res/images/progress_empty.png Binary files differindex 4cb4998dd..c6820159b 100644 --- a/res/images/progress_empty.png +++ b/res/images/progress_empty.png diff --git a/res/images/progress_fill.png b/res/images/progress_fill.png Binary files differindex eb71754db..9748435f5 100644 --- a/res/images/progress_fill.png +++ b/res/images/progress_fill.png @@ -14,19 +14,22 @@ * limitations under the License. */ +#include <errno.h> +#include <fcntl.h> #include <linux/input.h> #include <pthread.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sys/reboot.h> +#include <sys/stat.h> #include <sys/time.h> +#include <sys/types.h> #include <time.h> #include <unistd.h> -#include <errno.h> #include "common.h" +#include <cutils/android_reboot.h> #include "minui/minui.h" #include "recovery_ui.h" @@ -36,32 +39,32 @@ #define CHAR_WIDTH 10 #define CHAR_HEIGHT 18 -#define PROGRESSBAR_INDETERMINATE_STATES 6 -#define PROGRESSBAR_INDETERMINATE_FPS 15 - #define UI_WAIT_KEY_TIMEOUT_SEC 120 +UIParameters ui_parameters = { + 6, // indeterminate progress bar frames + 20, // fps + 7, // installation icon frames (0 == static image) + 23, 83, // installation icon overlay offset +}; + static pthread_mutex_t gUpdateMutex = PTHREAD_MUTEX_INITIALIZER; static gr_surface gBackgroundIcon[NUM_BACKGROUND_ICONS]; -static gr_surface gProgressBarIndeterminate[PROGRESSBAR_INDETERMINATE_STATES]; +static gr_surface *gInstallationOverlay; +static gr_surface *gProgressBarIndeterminate; static gr_surface gProgressBarEmpty; static gr_surface gProgressBarFill; static const struct { gr_surface* surface; const char *name; } BITMAPS[] = { { &gBackgroundIcon[BACKGROUND_ICON_INSTALLING], "icon_installing" }, { &gBackgroundIcon[BACKGROUND_ICON_ERROR], "icon_error" }, - { &gProgressBarIndeterminate[0], "indeterminate1" }, - { &gProgressBarIndeterminate[1], "indeterminate2" }, - { &gProgressBarIndeterminate[2], "indeterminate3" }, - { &gProgressBarIndeterminate[3], "indeterminate4" }, - { &gProgressBarIndeterminate[4], "indeterminate5" }, - { &gProgressBarIndeterminate[5], "indeterminate6" }, { &gProgressBarEmpty, "progress_empty" }, { &gProgressBarFill, "progress_fill" }, { NULL, NULL }, }; -static gr_surface gCurrentIcon = NULL; +static int gCurrentIcon = 0; +static int gInstallingFrame = 0; static enum ProgressBarType { PROGRESSBAR_TYPE_NONE, @@ -71,7 +74,7 @@ static enum ProgressBarType { // Progress bar scope of current operation static float gProgressScopeStart = 0, gProgressScopeSize = 0, gProgress = 0; -static time_t gProgressScopeTime, gProgressScopeDuration; +static double gProgressScopeTime, gProgressScopeDuration; // Set to 1 when both graphics pages are the same (except for the progress bar) static int gPagesIdentical = 0; @@ -93,20 +96,46 @@ static pthread_cond_t key_queue_cond = PTHREAD_COND_INITIALIZER; static int key_queue[256], key_queue_len = 0; static volatile char key_pressed[KEY_MAX + 1]; +// Return the current time as a double (including fractions of a second). +static double now() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + tv.tv_usec / 1000000.0; +} + +// Draw the given frame over the installation overlay animation. The +// background is not cleared or draw with the base icon first; we +// assume that the frame already contains some other frame of the +// animation. Does nothing if no overlay animation is defined. +// Should only be called with gUpdateMutex locked. +static void draw_install_overlay_locked(int frame) { + if (gInstallationOverlay == NULL) return; + gr_surface surface = gInstallationOverlay[frame]; + int iconWidth = gr_get_width(surface); + int iconHeight = gr_get_height(surface); + gr_blit(surface, 0, 0, iconWidth, iconHeight, + ui_parameters.install_overlay_offset_x, + ui_parameters.install_overlay_offset_y); +} + // Clear the screen and draw the currently selected background icon (if any). // Should only be called with gUpdateMutex locked. -static void draw_background_locked(gr_surface icon) +static void draw_background_locked(int icon) { gPagesIdentical = 0; gr_color(0, 0, 0, 255); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); if (icon) { - int iconWidth = gr_get_width(icon); - int iconHeight = gr_get_height(icon); + gr_surface surface = gBackgroundIcon[icon]; + int iconWidth = gr_get_width(surface); + int iconHeight = gr_get_height(surface); int iconX = (gr_fb_width() - iconWidth) / 2; int iconY = (gr_fb_height() - iconHeight) / 2; - gr_blit(icon, 0, 0, iconWidth, iconHeight, iconX, iconY); + gr_blit(surface, 0, 0, iconWidth, iconHeight, iconX, iconY); + if (icon == BACKGROUND_ICON_INSTALLING) { + draw_install_overlay_locked(gInstallingFrame); + } } } @@ -114,35 +143,39 @@ static void draw_background_locked(gr_surface icon) // Should only be called with gUpdateMutex locked. static void draw_progress_locked() { - if (gProgressBarType == PROGRESSBAR_TYPE_NONE) return; + if (gCurrentIcon == BACKGROUND_ICON_INSTALLING) { + draw_install_overlay_locked(gInstallingFrame); + } - int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]); - int width = gr_get_width(gProgressBarEmpty); - int height = gr_get_height(gProgressBarEmpty); + if (gProgressBarType != PROGRESSBAR_TYPE_NONE) { + int iconHeight = gr_get_height(gBackgroundIcon[BACKGROUND_ICON_INSTALLING]); + int width = gr_get_width(gProgressBarEmpty); + int height = gr_get_height(gProgressBarEmpty); - int dx = (gr_fb_width() - width)/2; - int dy = (3*gr_fb_height() + iconHeight - 2*height)/4; + int dx = (gr_fb_width() - width)/2; + int dy = (3*gr_fb_height() + iconHeight - 2*height)/4; - // Erase behind the progress bar (in case this was a progress-only update) - gr_color(0, 0, 0, 255); - gr_fill(dx, dy, width, height); + // Erase behind the progress bar (in case this was a progress-only update) + gr_color(0, 0, 0, 255); + gr_fill(dx, dy, width, height); - if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) { - float progress = gProgressScopeStart + gProgress * gProgressScopeSize; - int pos = (int) (progress * width); + if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL) { + float progress = gProgressScopeStart + gProgress * gProgressScopeSize; + int pos = (int) (progress * width); - if (pos > 0) { - gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy); - } - if (pos < width-1) { - gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy); + if (pos > 0) { + gr_blit(gProgressBarFill, 0, 0, pos, height, dx, dy); + } + if (pos < width-1) { + gr_blit(gProgressBarEmpty, pos, 0, width-pos, height, dx+pos, dy); + } } - } - if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) { - static int frame = 0; - gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy); - frame = (frame + 1) % PROGRESSBAR_INDETERMINATE_STATES; + if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE) { + static int frame = 0; + gr_blit(gProgressBarIndeterminate[frame], 0, 0, width, height, dx, dy); + frame = (frame + 1) % ui_parameters.indeterminate_frames; + } } } @@ -207,7 +240,7 @@ static void update_progress_locked(void) draw_screen_locked(); // Must redraw the whole screen gPagesIdentical = 1; } else { - draw_progress_locked(); // Draw only the progress bar + draw_progress_locked(); // Draw only the progress bar and overlays } gr_flip(); } @@ -215,29 +248,49 @@ static void update_progress_locked(void) // Keeps the progress bar updated, even when the process is otherwise busy. static void *progress_thread(void *cookie) { + double interval = 1.0 / ui_parameters.update_fps; for (;;) { - usleep(1000000 / PROGRESSBAR_INDETERMINATE_FPS); + double start = now(); pthread_mutex_lock(&gUpdateMutex); + int redraw = 0; + + // update the installation animation, if active + // skip this if we have a text overlay (too expensive to update) + if (gCurrentIcon == BACKGROUND_ICON_INSTALLING && + ui_parameters.installing_frames > 0 && + !show_text) { + gInstallingFrame = + (gInstallingFrame + 1) % ui_parameters.installing_frames; + redraw = 1; + } + // update the progress bar animation, if active // skip this if we have a text overlay (too expensive to update) if (gProgressBarType == PROGRESSBAR_TYPE_INDETERMINATE && !show_text) { - update_progress_locked(); + redraw = 1; } // move the progress bar forward on timed intervals, if configured int duration = gProgressScopeDuration; if (gProgressBarType == PROGRESSBAR_TYPE_NORMAL && duration > 0) { - int elapsed = time(NULL) - gProgressScopeTime; + double elapsed = now() - gProgressScopeTime; float progress = 1.0 * elapsed / duration; if (progress > 1.0) progress = 1.0; if (progress > gProgress) { gProgress = progress; - update_progress_locked(); + redraw = 1; } } + if (redraw) update_progress_locked(); + pthread_mutex_unlock(&gUpdateMutex); + double end = now(); + // minimum of 20ms delay between frames + double delay = interval - (end-start); + if (delay < 0.02) delay = 0.02; + usleep((long)(delay * 1000000)); } return NULL; } @@ -305,7 +358,7 @@ static void *input_thread(void *cookie) } if (ev.value > 0 && device_reboot_now(key_pressed, ev.code)) { - reboot(RB_AUTOBOOT); + android_reboot(ANDROID_RB_RESTART, 0, 0); } } return NULL; @@ -328,13 +381,47 @@ void ui_init(void) for (i = 0; BITMAPS[i].name != NULL; ++i) { int result = res_create_surface(BITMAPS[i].name, BITMAPS[i].surface); if (result < 0) { - if (result == -2) { - LOGI("Bitmap %s missing header\n", BITMAPS[i].name); - } else { - LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result); + LOGE("Missing bitmap %s\n(Code %d)\n", BITMAPS[i].name, result); + } + } + + gProgressBarIndeterminate = malloc(ui_parameters.indeterminate_frames * + sizeof(gr_surface)); + for (i = 0; i < ui_parameters.indeterminate_frames; ++i) { + char filename[40]; + // "indeterminate01.png", "indeterminate02.png", ... + sprintf(filename, "indeterminate%02d", i+1); + int result = res_create_surface(filename, gProgressBarIndeterminate+i); + if (result < 0) { + LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); + } + } + + if (ui_parameters.installing_frames > 0) { + gInstallationOverlay = malloc(ui_parameters.installing_frames * + sizeof(gr_surface)); + for (i = 0; i < ui_parameters.installing_frames; ++i) { + char filename[40]; + // "icon_installing_overlay01.png", + // "icon_installing_overlay02.png", ... + sprintf(filename, "icon_installing_overlay%02d", i+1); + int result = res_create_surface(filename, gInstallationOverlay+i); + if (result < 0) { + LOGE("Missing bitmap %s\n(Code %d)\n", filename, result); } - *BITMAPS[i].surface = NULL; } + + // Adjust the offset to account for the positioning of the + // base image on the screen. + if (gBackgroundIcon[BACKGROUND_ICON_INSTALLING] != NULL) { + gr_surface bg = gBackgroundIcon[BACKGROUND_ICON_INSTALLING]; + ui_parameters.install_overlay_offset_x += + (gr_fb_width() - gr_get_width(bg)) / 2; + ui_parameters.install_overlay_offset_y += + (gr_fb_height() - gr_get_height(bg)) / 2; + } + } else { + gInstallationOverlay = NULL; } pthread_t t; @@ -345,7 +432,7 @@ void ui_init(void) void ui_set_background(int icon) { pthread_mutex_lock(&gUpdateMutex); - gCurrentIcon = gBackgroundIcon[icon]; + gCurrentIcon = icon; update_screen_locked(); pthread_mutex_unlock(&gUpdateMutex); } @@ -366,7 +453,7 @@ void ui_show_progress(float portion, int seconds) gProgressBarType = PROGRESSBAR_TYPE_NORMAL; gProgressScopeStart += gProgressScopeSize; gProgressScopeSize = portion; - gProgressScopeTime = time(NULL); + gProgressScopeTime = now(); gProgressScopeDuration = seconds; gProgress = 0; update_progress_locked(); @@ -503,22 +590,44 @@ void ui_show_text(int visible) pthread_mutex_unlock(&gUpdateMutex); } +// Return true if USB is connected. +static int usb_connected() { + int fd = open("/sys/class/switch/usb_connected/state", O_RDONLY); + if (fd < 0) { + printf("failed to open /sys/class/switch/usb_connected/state: %s\n", + strerror(errno)); + return 0; + } + + char buf; + int connected = (read(fd, &buf, 1) == 1) && (buf == '1'); + if (close(fd) < 0) { + printf("failed to close /sys/class/switch/usb_connected/state: %s\n", + strerror(errno)); + } + return connected; +} + int ui_wait_key() { pthread_mutex_lock(&key_queue_mutex); - struct timeval now; - struct timespec timeout; - gettimeofday(&now, NULL); - timeout.tv_sec = now.tv_sec; - timeout.tv_nsec = now.tv_usec * 1000; - timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; - - int rc = 0; - while (key_queue_len == 0 && rc != ETIMEDOUT) { - rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, - &timeout); - } + // Time out after UI_WAIT_KEY_TIMEOUT_SEC, unless a USB cable is + // plugged in. + do { + struct timeval now; + struct timespec timeout; + gettimeofday(&now, NULL); + timeout.tv_sec = now.tv_sec; + timeout.tv_nsec = now.tv_usec * 1000; + timeout.tv_sec += UI_WAIT_KEY_TIMEOUT_SEC; + + int rc = 0; + while (key_queue_len == 0 && rc != ETIMEDOUT) { + rc = pthread_cond_timedwait(&key_queue_cond, &key_queue_mutex, + &timeout); + } + } while (usb_connected() && key_queue_len == 0); int key = -1; if (key_queue_len > 0) { diff --git a/updater/install.c b/updater/install.c index 6a7996467..0396bae6c 100644 --- a/updater/install.c +++ b/updater/install.c @@ -782,21 +782,26 @@ static bool write_raw_image_cb(const unsigned char* data, return false; } -// write_raw_image(file, partition) +// write_raw_image(filename_or_blob, partition) Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; - char* partition; - char* filename; - if (ReadArgs(state, argv, 2, &filename, &partition) < 0) { + Value* partition_value; + Value* contents; + if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) { return NULL; } + if (partition_value->type != VAL_STRING) { + ErrorAbort(state, "partition argument to %s must be string", name); + goto done; + } + char* partition = partition_value->data; if (strlen(partition) == 0) { ErrorAbort(state, "partition argument to %s can't be empty", name); goto done; } - if (strlen(filename) == 0) { + if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { ErrorAbort(state, "file argument to %s can't be empty", name); goto done; } @@ -819,27 +824,35 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { bool success; - FILE* f = fopen(filename, "rb"); - if (f == NULL) { - fprintf(stderr, "%s: can't open %s: %s\n", - name, filename, strerror(errno)); - result = strdup(""); - goto done; - } + if (contents->type == VAL_STRING) { + // we're given a filename as the contents + char* filename = contents->data; + FILE* f = fopen(filename, "rb"); + if (f == NULL) { + fprintf(stderr, "%s: can't open %s: %s\n", + name, filename, strerror(errno)); + result = strdup(""); + goto done; + } - success = true; - char* buffer = malloc(BUFSIZ); - int read; - while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { - int wrote = mtd_write_data(ctx, buffer, read); - success = success && (wrote == read); - if (!success) { - fprintf(stderr, "mtd_write_data to %s failed: %s\n", - partition, strerror(errno)); + success = true; + char* buffer = malloc(BUFSIZ); + int read; + while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { + int wrote = mtd_write_data(ctx, buffer, read); + success = success && (wrote == read); } + free(buffer); + fclose(f); + } else { + // we're given a blob as the contents + ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); + success = (wrote == contents->size); + } + if (!success) { + fprintf(stderr, "mtd_write_data to %s failed: %s\n", + partition, strerror(errno)); } - free(buffer); - fclose(f); if (mtd_erase_blocks(ctx, -1) == -1) { fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); @@ -848,14 +861,14 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { fprintf(stderr, "%s: error closing write of %s\n", name, partition); } - printf("%s %s partition from %s\n", - success ? "wrote" : "failed to write", partition, filename); + printf("%s %s partition\n", + success ? "wrote" : "failed to write", partition); result = success ? partition : strdup(""); done: - if (result != partition) free(partition); - free(filename); + if (result != partition) FreeValue(partition_value); + FreeValue(contents); return StringValue(result); } diff --git a/verifier.c b/verifier.c index 9d39fd139..729e085cf 100644 --- a/verifier.c +++ b/verifier.c @@ -173,7 +173,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey // the signing tool appends after the signature itself. if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, RSANUMBYTES, sha1)) { - LOGI("whole-file signature verified\n"); + LOGI("whole-file signature verified against key %d\n", i); free(eocd); return VERIFY_SUCCESS; } |