From e08991e02a7d678f2574e85289a34b2a9a537c82 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 2 Feb 2010 13:09:52 -0800 Subject: [PATCH] bump updater API version to 3; deprecate firmware update command Remove support for the HTC-specific "firmware" update command and the corresponding edify function write_firmware_update(). This functionality is now done by an edify extension library that lives in vendor/htc. Change-Id: I80858951ff10ed8dfff98aefb796bef009e05efb --- Android.mk | 3 +- bootloader.c | 249 --------------------------- bootloader.h | 16 -- common.h | 7 - firmware.c | 132 -------------- firmware.h | 36 ---- install.c | 91 +--------- recovery.c | 11 +- res/images/icon_firmware_error.png | Bin 8088 -> 0 bytes res/images/icon_firmware_install.png | Bin 12717 -> 0 bytes ui.c | 21 --- updater/install.c | 39 ----- updater/updater.c | 9 +- updater/updater.h | 1 + 14 files changed, 16 insertions(+), 599 deletions(-) delete mode 100644 firmware.c delete mode 100644 firmware.h delete mode 100644 res/images/icon_firmware_error.png delete mode 100755 res/images/icon_firmware_install.png diff --git a/Android.mk b/Android.mk index e89b225..5f74064 100644 --- a/Android.mk +++ b/Android.mk @@ -9,7 +9,6 @@ commands_recovery_local_path := $(LOCAL_PATH) LOCAL_SRC_FILES := \ recovery.c \ bootloader.c \ - firmware.c \ install.c \ roots.c \ ui.c \ @@ -22,7 +21,7 @@ LOCAL_MODULE := recovery LOCAL_FORCE_STATIC_EXECUTABLE := true -RECOVERY_API_VERSION := 2 +RECOVERY_API_VERSION := 3 LOCAL_CFLAGS += -DRECOVERY_API_VERSION=$(RECOVERY_API_VERSION) # This binary is in the recovery ramdisk, which is otherwise a copy of root. diff --git a/bootloader.c b/bootloader.c index 61b24e9..38b5651 100644 --- a/bootloader.c +++ b/bootloader.c @@ -119,252 +119,3 @@ int set_bootloader_message(const struct bootloader_message *in) { LOGI("Set boot command \"%s\"\n", in->command[0] != 255 ? in->command : ""); return 0; } - -/* Update Image - * - * - will be stored in the "cache" partition - * - bad blocks will be ignored, like boot.img and recovery.img - * - the first block will be the image header (described below) - * - the size is in BYTES, inclusive of the header - * - offsets are in BYTES from the start of the update header - * - two raw bitmaps will be included, the "busy" and "fail" bitmaps - * - for dream, the bitmaps will be 320x480x16bpp RGB565 - */ - -#define UPDATE_MAGIC "MSM-RADIO-UPDATE" -#define UPDATE_MAGIC_SIZE 16 -#define UPDATE_VERSION 0x00010000 - -struct update_header { - unsigned char MAGIC[UPDATE_MAGIC_SIZE]; - - unsigned version; - unsigned size; - - unsigned image_offset; - unsigned image_length; - - unsigned bitmap_width; - unsigned bitmap_height; - unsigned bitmap_bpp; - - unsigned busy_bitmap_offset; - unsigned busy_bitmap_length; - - unsigned fail_bitmap_offset; - unsigned fail_bitmap_length; -}; - -#define LOG_MAGIC "LOGmagic" -#define LOG_MAGIC_SIZE 8 - -int write_update_for_bootloader( - const char *update, int update_length, - int bitmap_width, int bitmap_height, int bitmap_bpp, - const char *busy_bitmap, const char *fail_bitmap, - const char *log_filename) { - if (ensure_root_path_unmounted(CACHE_NAME)) { - LOGE("Can't unmount %s\n", CACHE_NAME); - return -1; - } - - const MtdPartition *part = get_root_mtd_partition(CACHE_NAME); - if (part == NULL) { - LOGE("Can't find %s\n", CACHE_NAME); - return -1; - } - - MtdWriteContext *write = mtd_write_partition(part); - if (write == NULL) { - LOGE("Can't open %s\n(%s)\n", CACHE_NAME, strerror(errno)); - return -1; - } - - /* Write an invalid (zero) header first, to disable any previous - * update and any other structured contents (like a filesystem), - * and as a placeholder for the amount of space required. - */ - - struct update_header header; - memset(&header, 0, sizeof(header)); - const ssize_t header_size = sizeof(header); - if (mtd_write_data(write, (char*) &header, header_size) != header_size) { - LOGE("Can't write header to %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - - /* Write each section individually block-aligned, so we can write - * each block independently without complicated buffering. - */ - - memcpy(&header.MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE); - header.version = UPDATE_VERSION; - header.size = header_size; - - if (log_filename != NULL) { - // Write 1 byte into the following block, then fill to the end - // in order to reserve that block. We'll use the block to - // send a copy of the log through to the next invocation of - // recovery. We write the log as late as possible in order to - // capture any messages emitted by this function. - mtd_erase_blocks(write, 0); - if (mtd_write_data(write, (char*) &header, 1) != 1) { - LOGE("Can't write log block to %s\n(%s)\n", - CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - } - - off_t image_start_pos = mtd_erase_blocks(write, 0); - header.image_length = update_length; - if ((int) header.image_offset == -1 || - mtd_write_data(write, update, update_length) != update_length) { - LOGE("Can't write update to %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - off_t busy_start_pos = mtd_erase_blocks(write, 0); - header.image_offset = mtd_find_write_start(write, image_start_pos); - - header.bitmap_width = bitmap_width; - header.bitmap_height = bitmap_height; - header.bitmap_bpp = bitmap_bpp; - - int bitmap_length = (bitmap_bpp + 7) / 8 * bitmap_width * bitmap_height; - - header.busy_bitmap_length = busy_bitmap != NULL ? bitmap_length : 0; - if ((int) header.busy_bitmap_offset == -1 || - mtd_write_data(write, busy_bitmap, bitmap_length) != bitmap_length) { - LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - off_t fail_start_pos = mtd_erase_blocks(write, 0); - header.busy_bitmap_offset = mtd_find_write_start(write, busy_start_pos); - - header.fail_bitmap_length = fail_bitmap != NULL ? bitmap_length : 0; - if ((int) header.fail_bitmap_offset == -1 || - mtd_write_data(write, fail_bitmap, bitmap_length) != bitmap_length) { - LOGE("Can't write bitmap to %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - mtd_erase_blocks(write, 0); - header.fail_bitmap_offset = mtd_find_write_start(write, fail_start_pos); - - /* Write the header last, after all the blocks it refers to, so that - * when the magic number is installed everything is valid. - */ - - if (mtd_write_close(write)) { - LOGE("Can't finish writing %s\n(%s)\n", CACHE_NAME, strerror(errno)); - return -1; - } - - write = mtd_write_partition(part); - if (write == NULL) { - LOGE("Can't reopen %s\n(%s)\n", CACHE_NAME, strerror(errno)); - return -1; - } - - if (mtd_write_data(write, (char*) &header, header_size) != header_size) { - LOGE("Can't rewrite header to %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - - if (log_filename != NULL) { - size_t erase_size; - if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) { - LOGE("Error reading block size\n(%s)\n", strerror(errno)); - mtd_write_close(write); - return -1; - } - mtd_erase_blocks(write, 0); - - if (erase_size > 0) { - char* log = malloc(erase_size); - FILE* f = fopen(log_filename, "rb"); - // The fseek() may fail if it tries to go before the - // beginning of the log, but that's okay because we want - // to be positioned at the start anyway. - fseek(f, -(erase_size-sizeof(size_t)-LOG_MAGIC_SIZE), SEEK_END); - memcpy(log, LOG_MAGIC, LOG_MAGIC_SIZE); - size_t read = fread(log+sizeof(size_t)+LOG_MAGIC_SIZE, - 1, erase_size-sizeof(size_t)-LOG_MAGIC_SIZE, f); - LOGI("read %d bytes from log\n", (int)read); - *(size_t *)(log + LOG_MAGIC_SIZE) = read; - fclose(f); - if (mtd_write_data(write, log, erase_size) != erase_size) { - LOGE("failed to store log in cache partition\n(%s)\n", - strerror(errno)); - mtd_write_close(write); - } - free(log); - } - } - - if (mtd_erase_blocks(write, 0) != image_start_pos) { - LOGE("Misalignment rewriting %s\n(%s)\n", CACHE_NAME, strerror(errno)); - mtd_write_close(write); - return -1; - } - - if (mtd_write_close(write)) { - LOGE("Can't finish header of %s\n(%s)\n", CACHE_NAME, strerror(errno)); - return -1; - } - - return 0; -} - -void recover_firmware_update_log() { - printf("recovering log from before firmware update\n"); - - const MtdPartition *part = get_root_mtd_partition(CACHE_NAME); - if (part == NULL) { - LOGE("Can't find %s\n", CACHE_NAME); - return; - } - - MtdReadContext* read = mtd_read_partition(part); - - size_t erase_size; - if (mtd_partition_info(part, NULL, &erase_size, NULL) != 0) { - LOGE("Error reading block size\n(%s)\n", strerror(errno)); - mtd_read_close(read); - return; - } - - char* buffer = malloc(erase_size); - if (mtd_read_data(read, buffer, erase_size) != erase_size) { - LOGE("Error reading header block\n(%s)\n", strerror(errno)); - mtd_read_close(read); - free(buffer); - return; - } - if (mtd_read_data(read, buffer, erase_size) != erase_size) { - LOGE("Error reading log block\n(%s)\n", strerror(errno)); - mtd_read_close(read); - free(buffer); - return; - } - mtd_read_close(read); - - if (memcmp(buffer, LOG_MAGIC, LOG_MAGIC_SIZE) != 0) { - LOGE("No log from before firmware install\n"); - free(buffer); - return; - } - - size_t log_size = *(size_t *)(buffer + LOG_MAGIC_SIZE); - LOGI("header has %d bytes of log\n", (int)log_size); - - printf("\n###\n### START RECOVERED LOG\n###\n\n"); - fwrite(buffer + sizeof(size_t) + LOG_MAGIC_SIZE, 1, log_size, stdout); - printf("\n\n###\n### END RECOVERED LOG\n###\n\n"); - - free(buffer); -} diff --git a/bootloader.h b/bootloader.h index fec6409..2e749aa 100644 --- a/bootloader.h +++ b/bootloader.h @@ -47,20 +47,4 @@ struct bootloader_message { int get_bootloader_message(struct bootloader_message *out); int set_bootloader_message(const struct bootloader_message *in); -/* Write an update to the cache partition for update-radio or update-hboot. - * Note, this destroys any filesystem on the cache partition! - * The expected bitmap format is 240x320, 16bpp (2Bpp), RGB 5:6:5. - */ -int write_update_for_bootloader( - const char *update, int update_len, - int bitmap_width, int bitmap_height, int bitmap_bpp, - const char *busy_bitmap, const char *error_bitmap, - const char *log_filename); - -/* Look for a log stored in the cache partition in the block after the - * firmware update header. If we can read such a log, copy it to - * stdout (ie, the current log). - */ -void recover_firmware_update_log(); - #endif diff --git a/common.h b/common.h index d962a0a..ff577c2 100644 --- a/common.h +++ b/common.h @@ -49,17 +49,10 @@ enum { BACKGROUND_ICON_NONE, BACKGROUND_ICON_INSTALLING, BACKGROUND_ICON_ERROR, - BACKGROUND_ICON_FIRMWARE_INSTALLING, - BACKGROUND_ICON_FIRMWARE_ERROR, NUM_BACKGROUND_ICONS }; void ui_set_background(int icon); -// Get a malloc'd copy of the screen image showing (only) the specified icon. -// Also returns the width, height, and bits per pixel of the returned image. -// TODO: Use some sort of "struct Bitmap" here instead of all these variables? -char *ui_copy_image(int icon, int *width, int *height, int *bpp); - // Show a progress bar and define the scope of the next operation: // portion - fraction of the progress bar the next operation will use // seconds - expected time interval (progress bar moves at this minimum rate) diff --git a/firmware.c b/firmware.c deleted file mode 100644 index 4c1a9a4..0000000 --- a/firmware.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2008 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 "bootloader.h" -#include "common.h" -#include "firmware.h" -#include "roots.h" - -#include -#include -#include - -static const char *update_type = NULL; -static const char *update_data = NULL; -static int update_length = 0; - -int remember_firmware_update(const char *type, const char *data, int length) { - if (update_type != NULL || update_data != NULL) { - LOGE("Multiple firmware images\n"); - return -1; - } - - update_type = type; - update_data = data; - update_length = length; - return 0; -} - -// Return true if there is a firmware update pending. -int firmware_update_pending() { - return update_data != NULL && update_length > 0; -} - -/* Bootloader / Recovery Flow - * - * On every boot, the bootloader will read the bootloader_message - * from flash and check the command field. The bootloader should - * deal with the command field not having a 0 terminator correctly - * (so as to not crash if the block is invalid or corrupt). - * - * The bootloader will have to publish the partition that contains - * the bootloader_message to the linux kernel so it can update it. - * - * if command == "boot-recovery" -> boot recovery.img - * else if command == "update-radio" -> update radio image (below) - * else if command == "update-hboot" -> update hboot image (below) - * else -> boot boot.img (normal boot) - * - * Radio/Hboot Update Flow - * 1. the bootloader will attempt to load and validate the header - * 2. if the header is invalid, status="invalid-update", goto #8 - * 3. display the busy image on-screen - * 4. if the update image is invalid, status="invalid-radio-image", goto #8 - * 5. attempt to update the firmware (depending on the command) - * 6. if successful, status="okay", goto #8 - * 7. if failed, and the old image can still boot, status="failed-update" - * 8. write the bootloader_message, leaving the recovery field - * unchanged, updating status, and setting command to - * "boot-recovery" - * 9. reboot - * - * The bootloader will not modify or erase the cache partition. - * It is recovery's responsibility to clean up the mess afterwards. - */ - -int maybe_install_firmware_update(const char *send_intent, - const char *log_filename) { - if (update_data == NULL || update_length == 0) return 0; - - /* We destroy the cache partition to pass the update image to the - * bootloader, so all we can really do afterwards is wipe cache and reboot. - * Set up this instruction now, in case we're interrupted while writing. - */ - - struct bootloader_message boot; - memset(&boot, 0, sizeof(boot)); - strlcpy(boot.command, "boot-recovery", sizeof(boot.command)); - strlcpy(boot.recovery, "recovery\n--wipe_cache\n", sizeof(boot.command)); - if (send_intent != NULL) { - strlcat(boot.recovery, "--send_intent=", sizeof(boot.recovery)); - strlcat(boot.recovery, send_intent, sizeof(boot.recovery)); - strlcat(boot.recovery, "\n", sizeof(boot.recovery)); - } - if (set_bootloader_message(&boot)) return -1; - - int width = 0, height = 0, bpp = 0; - char *busy_image = ui_copy_image( - BACKGROUND_ICON_FIRMWARE_INSTALLING, &width, &height, &bpp); - char *fail_image = ui_copy_image( - BACKGROUND_ICON_FIRMWARE_ERROR, &width, &height, &bpp); - - ui_print("Writing %s image...\n", update_type); - if (write_update_for_bootloader( - update_data, update_length, - width, height, bpp, busy_image, fail_image, log_filename)) { - LOGE("Can't write %s image\n(%s)\n", update_type, strerror(errno)); - format_root_device("CACHE:"); // Attempt to clean cache up, at least. - return -1; - } - - free(busy_image); - free(fail_image); - - /* The update image is fully written, so now we can instruct the bootloader - * to install it. (After doing so, it will come back here, and we will - * wipe the cache and reboot into the system.) - */ - snprintf(boot.command, sizeof(boot.command), "update-%s", update_type); - if (set_bootloader_message(&boot)) { - format_root_device("CACHE:"); - return -1; - } - - reboot(RB_AUTOBOOT); - - // Can't reboot? WTF? - LOGE("Can't reboot\n"); - return -1; -} diff --git a/firmware.h b/firmware.h deleted file mode 100644 index 04507bb..0000000 --- a/firmware.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef _RECOVERY_FIRMWARE_H -#define _RECOVERY_FIRMWARE_H - -/* Save a radio or bootloader update image for later installation. - * The type should be one of "hboot" or "radio". - * Takes ownership of type and data. Returns nonzero on error. - */ -int remember_firmware_update(const char *type, const char *data, int length); - -/* Returns true if a firmware update has been saved. */ -int firmware_update_pending(); - -/* If an update was saved, reboot into the bootloader now to install it. - * Returns 0 if no radio image was defined, nonzero on error, - * doesn't return at all on success... - */ -int maybe_install_firmware_update(const char *send_intent, - const char *log_filename); - -#endif diff --git a/install.c b/install.c index bb9924a..37a4f07 100644 --- a/install.c +++ b/install.c @@ -32,71 +32,10 @@ #include "mtdutils/mtdutils.h" #include "roots.h" #include "verifier.h" -#include "firmware.h" #define ASSUMED_UPDATE_BINARY_NAME "META-INF/com/google/android/update-binary" #define PUBLIC_KEYS_FILE "/res/keys" -// The update binary ask us to install a firmware file on reboot. Set -// that up. Takes ownership of type and filename. -static int -handle_firmware_update(char* type, char* filename, ZipArchive* zip) { - unsigned int data_size; - const ZipEntry* entry = NULL; - - if (strncmp(filename, "PACKAGE:", 8) == 0) { - entry = mzFindZipEntry(zip, filename+8); - if (entry == NULL) { - LOGE("Failed to find \"%s\" in package", filename+8); - return INSTALL_ERROR; - } - data_size = entry->uncompLen; - } else { - struct stat st_data; - if (stat(filename, &st_data) < 0) { - LOGE("Error stat'ing %s: %s\n", filename, strerror(errno)); - return INSTALL_ERROR; - } - data_size = st_data.st_size; - } - - LOGI("type is %s; size is %d; file is %s\n", - type, data_size, filename); - - char* data = malloc(data_size); - if (data == NULL) { - LOGI("Can't allocate %d bytes for firmware data\n", data_size); - return INSTALL_ERROR; - } - - if (entry) { - if (mzReadZipEntry(zip, entry, data, data_size) == false) { - LOGE("Failed to read \"%s\" from package", filename+8); - return INSTALL_ERROR; - } - } else { - FILE* f = fopen(filename, "rb"); - if (f == NULL) { - LOGE("Failed to open %s: %s\n", filename, strerror(errno)); - return INSTALL_ERROR; - } - if (fread(data, 1, data_size, f) != data_size) { - LOGE("Failed to read firmware data: %s\n", strerror(errno)); - return INSTALL_ERROR; - } - fclose(f); - } - - if (remember_firmware_update(type, data, data_size)) { - LOGE("Can't store %s image\n", type); - free(data); - return INSTALL_ERROR; - } - free(filename); - - return INSTALL_SUCCESS; -} - // If the package contains an update binary, extract it and run it. static int try_update_binary(const char *path, ZipArchive *zip) { @@ -145,9 +84,12 @@ try_update_binary(const char *path, ZipArchive *zip) { // // firmware <"hboot"|"radio"> // arrange to install the contents of in the - // given partition on reboot. (API v2: may - // start with "PACKAGE:" to indicate taking a file from - // the OTA package.) + // given partition on reboot. + // + // (API v2: may start with "PACKAGE:" to + // indicate taking a file from the OTA package.) + // + // (API v3: this command no longer exists.) // // ui_print // display on the screen. @@ -172,9 +114,6 @@ try_update_binary(const char *path, ZipArchive *zip) { } close(pipefd[1]); - char* firmware_type = NULL; - char* firmware_filename = NULL; - char buffer[1024]; FILE* from_child = fdopen(pipefd[0], "r"); while (fgets(buffer, sizeof(buffer), from_child) != NULL) { @@ -194,18 +133,6 @@ try_update_binary(const char *path, ZipArchive *zip) { char* fraction_s = strtok(NULL, " \n"); float fraction = strtof(fraction_s, NULL); ui_set_progress(fraction); - } else if (strcmp(command, "firmware") == 0) { - char* type = strtok(NULL, " \n"); - char* filename = strtok(NULL, " \n"); - - if (type != NULL && filename != NULL) { - if (firmware_type != NULL) { - LOGE("ignoring attempt to do multiple firmware updates"); - } else { - firmware_type = strdup(type); - firmware_filename = strdup(filename); - } - } } else if (strcmp(command, "ui_print") == 0) { char* str = strtok(NULL, "\n"); if (str) { @@ -226,11 +153,7 @@ try_update_binary(const char *path, ZipArchive *zip) { return INSTALL_ERROR; } - if (firmware_type != NULL) { - return handle_firmware_update(firmware_type, firmware_filename, zip); - } else { - return INSTALL_SUCCESS; - } + return INSTALL_SUCCESS; } static int diff --git a/recovery.c b/recovery.c index 73a54a2..4c437e5 100644 --- a/recovery.c +++ b/recovery.c @@ -31,7 +31,6 @@ #include "bootloader.h" #include "common.h" #include "cutils/properties.h" -#include "firmware.h" #include "install.h" #include "minui/minui.h" #include "minzip/DirUtil.h" @@ -445,12 +444,7 @@ prompt_and_wait() { } else if (!ui_text_visible()) { return; // reboot if logs aren't visible } else { - if (firmware_update_pending()) { - ui_print("\nReboot via menu to complete\n" - "installation.\n"); - } else { - ui_print("\nInstall from sdcard complete.\n"); - } + ui_print("\nInstall from sdcard complete.\n"); } break; } @@ -563,9 +557,6 @@ main(int argc, char **argv) { if (status != INSTALL_SUCCESS) ui_set_background(BACKGROUND_ICON_ERROR); if (status != INSTALL_SUCCESS || ui_text_visible()) prompt_and_wait(); - // If there is a radio image pending, reboot now to install it. - maybe_install_firmware_update(send_intent, TEMPORARY_LOG_FILE); - // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui_print("Rebooting...\n"); diff --git a/res/images/icon_firmware_error.png b/res/images/icon_firmware_error.png deleted file mode 100644 index 0c32c9ede10471bf1b40f37928048ba0edef9ef4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8088 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 HW*hN;6<-!8 diff --git a/res/images/icon_firmware_install.png b/res/images/icon_firmware_install.png deleted file mode 100755 index 2da9e5ffe6bc90d78e179f86382980586ab9f809..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12717 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 - fprintf(cmd, "firmware %s %s\n", partition, filename); - - printf("will write %s firmware from %s\n", partition, filename); - result = partition; - -done: - if (result != partition) free(partition); - free(filename); - return result; -} - - extern int applypatch(int argc, char** argv); // apply_patch(srcfile, tgtfile, tgtsha1, tgtsize, sha1:patch, ...) @@ -888,7 +850,6 @@ void RegisterInstallFunctions() { RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("write_raw_image", WriteRawImageFn); - RegisterFunction("write_firmware_image", WriteFirmwareImageFn); RegisterFunction("apply_patch", ApplyPatchFn); RegisterFunction("apply_patch_check", ApplyPatchFn); diff --git a/updater/updater.c b/updater/updater.c index 1aa277c..2d16dee 100644 --- a/updater/updater.c +++ b/updater/updater.c @@ -39,9 +39,11 @@ int main(int argc, char** argv) { } char* version = argv[1]; - if ((version[0] != '1' && version[0] != '2') || version[1] != '\0') { - // We support version "1" or "2". - fprintf(stderr, "wrong updater binary API; expected 1 or 2, got %s\n", + if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || + version[1] != '\0') { + // We support version 1, 2, or 3. + fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; " + "got %s\n", argv[1]); return 2; } @@ -100,6 +102,7 @@ int main(int argc, char** argv) { UpdaterInfo updater_info; updater_info.cmd_pipe = cmd_pipe; updater_info.package_zip = &za; + updater_info.version = atoi(version); State state; state.cookie = &updater_info; diff --git a/updater/updater.h b/updater/updater.h index 22fbfd2..bd60dc1 100644 --- a/updater/updater.h +++ b/updater/updater.h @@ -23,6 +23,7 @@ typedef struct { FILE* cmd_pipe; ZipArchive* package_zip; + int version; } UpdaterInfo; #endif