diff options
Diffstat (limited to 'updater')
-rw-r--r-- | updater/Android.mk | 115 | ||||
-rw-r--r-- | updater/blockimg.cpp | 267 | ||||
-rw-r--r-- | updater/include/updater/blockimg.h (renamed from updater/blockimg.h) | 0 | ||||
-rw-r--r-- | updater/include/updater/install.h (renamed from updater/install.h) | 7 | ||||
-rw-r--r-- | updater/include/updater/updater.h (renamed from updater/updater.h) | 8 | ||||
-rw-r--r-- | updater/install.cpp | 544 | ||||
-rw-r--r-- | updater/updater.cpp | 98 |
7 files changed, 430 insertions, 609 deletions
diff --git a/updater/Android.mk b/updater/Android.mk index d7aa613e9..3c1d0d41f 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -14,52 +14,87 @@ LOCAL_PATH := $(call my-dir) -updater_src_files := \ - install.cpp \ - blockimg.cpp \ - updater.cpp - -# -# Build a statically-linked binary to include in OTA packages -# +tune2fs_static_libraries := \ + libext2_com_err \ + libext2_blkid \ + libext2_quota \ + libext2_uuid_static \ + libext2_e2p \ + libext2fs + +updater_common_static_libraries := \ + libapplypatch \ + libedify \ + libziparchive \ + libotautil \ + libutils \ + libmounts \ + libotafault \ + libext4_utils_static \ + libfec \ + libfec_rs \ + liblog \ + libselinux \ + libsparse_static \ + libsquashfs_utils \ + libbz \ + libz \ + libbase \ + libcrypto \ + libcrypto_utils \ + libcutils \ + libtune2fs \ + $(tune2fs_static_libraries) + +# libupdater (static library) +# =============================== include $(CLEAR_VARS) -# Build only in eng, so we don't end up with a copy of this in /system -# on user builds. (TODO: find a better way to build device binaries -# needed only for OTA packages.) -LOCAL_MODULE_TAGS := eng +LOCAL_MODULE := libupdater -LOCAL_CLANG := true +LOCAL_SRC_FILES := \ + install.cpp \ + blockimg.cpp -LOCAL_SRC_FILES := $(updater_src_files) +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/.. \ + $(LOCAL_PATH)/include \ + external/e2fsprogs/misc -LOCAL_STATIC_LIBRARIES += libfec libfec_rs libext4_utils_static libsquashfs_utils libcrypto_static +LOCAL_CFLAGS := \ + -Wno-unused-parameter \ + -Werror -ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) -LOCAL_CFLAGS += -DUSE_EXT4 -LOCAL_CFLAGS += -Wno-unused-parameter -LOCAL_C_INCLUDES += system/extras/ext4_utils -LOCAL_STATIC_LIBRARIES += \ - libsparse_static \ - libz -endif - -LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz -LOCAL_STATIC_LIBRARIES += libbz -LOCAL_STATIC_LIBRARIES += libcutils liblog libc -LOCAL_STATIC_LIBRARIES += libselinux -tune2fs_static_libraries := \ - libext2_com_err \ - libext2_blkid \ - libext2_quota \ - libext2_uuid_static \ - libext2_e2p \ - libext2fs -LOCAL_STATIC_LIBRARIES += libtune2fs $(tune2fs_static_libraries) +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/include + +LOCAL_STATIC_LIBRARIES := \ + $(updater_common_static_libraries) + +include $(BUILD_STATIC_LIBRARY) -LOCAL_C_INCLUDES += external/e2fsprogs/misc -LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. +# updater (static executable) +# =============================== +include $(CLEAR_VARS) + +LOCAL_MODULE := updater + +LOCAL_SRC_FILES := \ + updater.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/.. \ + $(LOCAL_PATH)/include + +LOCAL_CFLAGS := \ + -Wno-unused-parameter \ + -Werror + +LOCAL_STATIC_LIBRARIES := \ + libupdater \ + $(TARGET_RECOVERY_UPDATER_LIBS) \ + $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \ + $(updater_common_static_libraries) # Each library in TARGET_RECOVERY_UPDATER_LIBS should have a function # named "Register_<libname>()". Here we emit a little C function that @@ -100,8 +135,6 @@ LOCAL_C_INCLUDES += $(dir $(inc)) inc := inc_dep_file := -LOCAL_MODULE := updater - LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_EXECUTABLE) diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index a80180a9a..f08ca5b0c 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -33,24 +33,24 @@ #include <unistd.h> #include <fec/io.h> -#include <map> #include <memory> #include <string> +#include <unordered_map> #include <vector> #include <android-base/parseint.h> #include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <ziparchive/zip_archive.h> #include "applypatch/applypatch.h" #include "edify/expr.h" #include "error_code.h" -#include "install.h" +#include "updater/install.h" #include "openssl/sha.h" -#include "minzip/Hash.h" #include "ota_io.h" #include "print_sha1.h" -#include "unique_fd.h" -#include "updater.h" +#include "updater/updater.h" #define BLOCKSIZE 4096 @@ -71,7 +71,7 @@ struct RangeSet { static CauseCode failure_type = kNoCause; static bool is_retry = false; -static std::map<std::string, RangeSet> stash_map; +static std::unordered_map<std::string, RangeSet> stash_map; static void parse_range(const std::string& range_text, RangeSet& rs) { @@ -151,6 +151,10 @@ static int read_all(int fd, uint8_t* data, size_t size) { failure_type = kFreadFailure; fprintf(stderr, "read failed: %s\n", strerror(errno)); return -1; + } else if (r == 0) { + failure_type = kFreadFailure; + fprintf(stderr, "read reached unexpected EOF.\n"); + return -1; } so_far += r; } @@ -213,7 +217,7 @@ static void allocate(size_t size, std::vector<uint8_t>& buffer) { } struct RangeSinkState { - RangeSinkState(RangeSet& rs) : tgt(rs) { }; + explicit RangeSinkState(RangeSet& rs) : tgt(rs) { }; int fd; const RangeSet& tgt; @@ -296,8 +300,8 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) { // rss and signals the condition again. struct NewThreadInfo { - ZipArchive* za; - const ZipEntry* entry; + ZipArchiveHandle za; + ZipEntry entry; RangeSinkState* rss; @@ -305,7 +309,7 @@ struct NewThreadInfo { pthread_cond_t cv; }; -static bool receive_new_data(const unsigned char* data, int size, void* cookie) { +static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) { NewThreadInfo* nti = reinterpret_cast<NewThreadInfo*>(cookie); while (size > 0) { @@ -338,7 +342,7 @@ static bool receive_new_data(const unsigned char* data, int size, void* cookie) static void* unzip_new_data(void* cookie) { NewThreadInfo* nti = (NewThreadInfo*) cookie; - mzProcessZipEntryContents(nti->za, nti->entry, receive_new_data, nti); + ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti); return nullptr; } @@ -398,7 +402,7 @@ struct CommandParameters { std::string stashbase; bool canwrite; int createdstash; - int fd; + android::base::unique_fd fd; bool foundwrites; bool isunresumable; int version; @@ -608,9 +612,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s return -1; } - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY)); - unique_fd fd_holder(fd); - + android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY))); if (fd == -1) { fprintf(stderr, "open \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); return -1; @@ -665,9 +667,9 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str()); - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)); - unique_fd fd_holder(fd); - + android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), + O_WRONLY | O_CREAT | O_TRUNC, + STASH_FILE_MODE))); if (fd == -1) { fprintf(stderr, "failed to create \"%s\": %s\n", fn.c_str(), strerror(errno)); return -1; @@ -690,9 +692,8 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } std::string dname = GetStashFileName(base, "", ""); - int dfd = TEMP_FAILURE_RETRY(open(dname.c_str(), O_RDONLY | O_DIRECTORY)); - unique_fd dfd_holder(dfd); - + android::base::unique_fd dfd(TEMP_FAILURE_RETRY(ota_open(dname.c_str(), + O_RDONLY | O_DIRECTORY))); if (dfd == -1) { failure_type = kFileOpenFailure; fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); @@ -980,8 +981,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& tgthash = params.tokens[params.cpos++]; } - if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, params.stashbase, - &overlap) == -1) { + if (LoadSrcTgtVersion2(params, tgt, src_blocks, params.buffer, params.fd, + params.stashbase, &overlap) == -1) { return -1; } @@ -1215,7 +1216,7 @@ static int PerformCommandDiff(CommandParameters& params) { size_t len; if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) { - fprintf(stderr, "invalid patch offset\n"); + fprintf(stderr, "invalid patch len\n"); return -1; } @@ -1247,10 +1248,8 @@ static int PerformCommandDiff(CommandParameters& params) { if (status == 0) { fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size); - Value patch_value; - patch_value.type = VAL_BLOB; - patch_value.size = len; - patch_value.data = (char*) (params.patch_start + offset); + Value patch_value(VAL_BLOB, + std::string(reinterpret_cast<const char*>(params.patch_start + offset), len)); RangeSinkState rss(tgt); rss.fd = params.fd; @@ -1352,28 +1351,6 @@ struct Command { CommandFunction f; }; -// CompareCommands and CompareCommandNames are for the hash table - -static int CompareCommands(const void* c1, const void* c2) { - return strcmp(((const Command*) c1)->name, ((const Command*) c2)->name); -} - -static int CompareCommandNames(const void* c1, const void* c2) { - return strcmp(((const Command*) c1)->name, (const char*) c2); -} - -// HashString is used to hash command names for the hash table - -static unsigned int HashString(const char *s) { - unsigned int hash = 0; - if (s) { - while (*s) { - hash = hash * 33 + *s++; - } - } - return hash; -} - // args: // - block device (or file) to modify in-place // - transfer list (blob) @@ -1382,8 +1359,7 @@ static unsigned int HashString(const char *s) { static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[], const Command* commands, size_t cmdcount, bool dryrun) { - CommandParameters params; - memset(¶ms, 0, sizeof(params)); + CommandParameters params = {}; params.canwrite = !dryrun; fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update"); @@ -1398,66 +1374,64 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg Value* patch_data_fn = nullptr; if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value, &new_data_fn, &patch_data_fn) < 0) { - return StringValue(strdup("")); + return StringValue(""); } - std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename, - FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> transfer_list_value_holder(transfer_list_value, - FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> new_data_fn_holder(new_data_fn, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> patch_data_fn_holder(patch_data_fn, FreeValue); + std::unique_ptr<Value> blockdev_filename_holder(blockdev_filename); + std::unique_ptr<Value> transfer_list_value_holder(transfer_list_value); + std::unique_ptr<Value> new_data_fn_holder(new_data_fn); + std::unique_ptr<Value> patch_data_fn_holder(patch_data_fn); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (transfer_list_value->type != VAL_BLOB) { ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name); - return StringValue(strdup("")); + return StringValue(""); } if (new_data_fn->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (patch_data_fn->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie); if (ui == nullptr) { - return StringValue(strdup("")); + return StringValue(""); } FILE* cmd_pipe = ui->cmd_pipe; - ZipArchive* za = ui->package_zip; + ZipArchiveHandle za = ui->package_zip; if (cmd_pipe == nullptr || za == nullptr) { - return StringValue(strdup("")); + return StringValue(""); } - const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data); - if (patch_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data); - return StringValue(strdup("")); + ZipString path_data(patch_data_fn->data.c_str()); + ZipEntry patch_entry; + if (FindEntry(za, path_data, &patch_entry) != 0) { + fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data.c_str()); + return StringValue(""); } - params.patch_start = ui->package_zip_addr + mzGetZipEntryOffset(patch_entry); - const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data); - if (new_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data); - return StringValue(strdup("")); + params.patch_start = ui->package_zip_addr + patch_entry.offset; + ZipString new_data(new_data_fn->data.c_str()); + ZipEntry new_entry; + if (FindEntry(za, new_data, &new_entry) != 0) { + fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str()); + return StringValue(""); } - params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR)); - unique_fd fd_holder(params.fd); - + params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR))); if (params.fd == -1) { - fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno)); - return StringValue(strdup("")); + fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } if (params.canwrite) { @@ -1473,24 +1447,21 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg int error = pthread_create(¶ms.thread, &attr, unzip_new_data, ¶ms.nti); if (error != 0) { fprintf(stderr, "pthread_create failed: %s\n", strerror(error)); - return StringValue(strdup("")); + return StringValue(""); } } - // Copy all the lines in transfer_list_value into std::string for - // processing. - const std::string transfer_list(transfer_list_value->data, transfer_list_value->size); - std::vector<std::string> lines = android::base::Split(transfer_list, "\n"); + std::vector<std::string> lines = android::base::Split(transfer_list_value->data, "\n"); if (lines.size() < 2) { ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zd]\n", lines.size()); - return StringValue(strdup("")); + return StringValue(""); } // First line in transfer list is the version number if (!android::base::ParseInt(lines[0].c_str(), ¶ms.version, 1, 4)) { fprintf(stderr, "unexpected transfer list version [%s]\n", lines[0].c_str()); - return StringValue(strdup("")); + return StringValue(""); } fprintf(stderr, "blockimg version is %d\n", params.version); @@ -1499,11 +1470,11 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg int total_blocks; if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) { ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str()); - return StringValue(strdup("")); + return StringValue(""); } if (total_blocks == 0) { - return StringValue(strdup("t")); + return StringValue("t"); } size_t start = 2; @@ -1511,7 +1482,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg if (lines.size() < 4) { ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", lines.size()); - return StringValue(strdup("")); + return StringValue(""); } // Third line is how many stash entries are needed simultaneously @@ -1522,12 +1493,12 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) { ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n", lines[3].c_str()); - return StringValue(strdup("")); + return StringValue(""); } - int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase); + int res = CreateStash(state, stash_max_blocks, blockdev_filename->data.c_str(), params.stashbase); if (res == -1) { - return StringValue(strdup("")); + return StringValue(""); } params.createdstash = res; @@ -1535,13 +1506,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg start += 2; } - // Build a hash table of the available commands - HashTable* cmdht = mzHashTableCreate(cmdcount, nullptr); - std::unique_ptr<HashTable, decltype(&mzHashTableFree)> cmdht_holder(cmdht, mzHashTableFree); - + // Build a map of the available commands + std::unordered_map<std::string, const Command*> cmd_map; for (size_t i = 0; i < cmdcount; ++i) { - unsigned int cmdhash = HashString(commands[i].name); - mzHashTableLookup(cmdht, cmdhash, (void*) &commands[i], CompareCommands, true); + if (cmd_map.find(commands[i].name) != cmd_map.end()) { + fprintf(stderr, "Error: command [%s] already exists in the cmd map.\n", + commands[i].name); + return StringValue(strdup("")); + } + cmd_map[commands[i].name] = &commands[i]; } int rc = -1; @@ -1558,16 +1531,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg params.cmdname = params.tokens[params.cpos++].c_str(); params.cmdline = line_str.c_str(); - unsigned int cmdhash = HashString(params.cmdname); - const Command* cmd = reinterpret_cast<const Command*>(mzHashTableLookup(cmdht, cmdhash, - const_cast<char*>(params.cmdname), CompareCommandNames, - false)); - - if (cmd == nullptr) { + if (cmd_map.find(params.cmdname) == cmd_map.end()) { fprintf(stderr, "unexpected command [%s]\n", params.cmdname); goto pbiudone; } + const Command* cmd = cmd_map[params.cmdname]; + if (cmd->f != nullptr && cmd->f(params) == -1) { fprintf(stderr, "failed to execute command [%s]\n", line_str.c_str()); goto pbiudone; @@ -1591,7 +1561,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg fprintf(stderr, "stashed %zu blocks\n", params.stashed); fprintf(stderr, "max alloc needed was %zu\n", params.buffer.size()); - const char* partition = strrchr(blockdev_filename->data, '/'); + const char* partition = strrchr(blockdev_filename->data.c_str(), '/'); if (partition != nullptr && *(partition+1) != 0) { fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE); @@ -1613,7 +1583,7 @@ pbiudone: failure_type = kFsyncFailure; fprintf(stderr, "fsync failed: %s\n", strerror(errno)); } - // params.fd will be automatically closed because of the fd_holder above. + // params.fd will be automatically closed because it's a unique_fd. // Only delete the stash if the update cannot be resumed, or it's // a verification run and we created the stash. @@ -1625,7 +1595,7 @@ pbiudone: state->cause_code = failure_type; } - return StringValue(rc == 0 ? strdup("t") : strdup("")); + return StringValue(rc == 0 ? "t" : ""); } // The transfer list is a text file containing commands to @@ -1723,28 +1693,26 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) Value* ranges; if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) { - return StringValue(strdup("")); + return StringValue(""); } - std::unique_ptr<Value, decltype(&FreeValue)> ranges_holder(ranges, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> blockdev_filename_holder(blockdev_filename, - FreeValue); + std::unique_ptr<Value> ranges_holder(ranges); + std::unique_ptr<Value> blockdev_filename_holder(blockdev_filename); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (ranges->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } - int fd = open(blockdev_filename->data, O_RDWR); - unique_fd fd_holder(fd); - if (fd < 0) { - ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + android::base::unique_fd fd(ota_open(blockdev_filename->data.c_str(), O_RDWR)); + if (fd == -1) { + ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } RangeSet rs; @@ -1756,16 +1724,16 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) std::vector<uint8_t> buffer(BLOCKSIZE); for (size_t i = 0; i < rs.count; ++i) { if (!check_lseek(fd, (off64_t)rs.pos[i*2] * BLOCKSIZE, SEEK_SET)) { - ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + ErrorAbort(state, kLseekFailure, "failed to seek %s: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) { if (read_all(fd, buffer, BLOCKSIZE) == -1) { - ErrorAbort(state, kFreadFailure, "failed to read %s: %s", blockdev_filename->data, - strerror(errno)); - return StringValue(strdup("")); + ErrorAbort(state, kFreadFailure, "failed to read %s: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } SHA1_Update(&ctx, buffer.data(), BLOCKSIZE); @@ -1774,7 +1742,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) uint8_t digest[SHA_DIGEST_LENGTH]; SHA1_Final(digest, &ctx); - return StringValue(strdup(print_sha1(digest).c_str())); + return StringValue(print_sha1(digest)); } // This function checks if a device has been remounted R/W prior to an incremental @@ -1788,28 +1756,27 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) if (ReadValueArgs(state, argv, 1, &arg_filename) < 0) { return nullptr; } - std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue); + std::unique_ptr<Value> filename(arg_filename); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } - int fd = open(arg_filename->data, O_RDONLY); - unique_fd fd_holder(fd); + android::base::unique_fd fd(ota_open(arg_filename->data.c_str(), O_RDONLY)); if (fd == -1) { - ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data, + ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", arg_filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } RangeSet blk0 {1 /*count*/, 1/*size*/, std::vector<size_t> {0, 1}/*position*/}; std::vector<uint8_t> block0_buffer(BLOCKSIZE); if (ReadBlocks(blk0, block0_buffer, fd) == -1) { - ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data, + ErrorAbort(state, kFreadFailure, "failed to read %s: %s", arg_filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } // https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout @@ -1827,7 +1794,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) uiPrintf(state, "Last remount happened on %s", ctime(&mount_time)); } - return StringValue(strdup("t")); + return StringValue("t"); } @@ -1839,40 +1806,40 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ return NULL; } - std::unique_ptr<Value, decltype(&FreeValue)> filename(arg_filename, FreeValue); - std::unique_ptr<Value, decltype(&FreeValue)> ranges(arg_ranges, FreeValue); + std::unique_ptr<Value> filename(arg_filename); + std::unique_ptr<Value> ranges(arg_ranges); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } if (ranges->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "ranges argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } // Output notice to log when recover is attempted - fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data); + fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data.c_str()); // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read - fec::io fh(filename->data, O_RDWR); + fec::io fh(filename->data.c_str(), O_RDWR); if (!fh) { - ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data, + ErrorAbort(state, kLibfecFailure, "fec_open \"%s\" failed: %s", filename->data.c_str(), strerror(errno)); - return StringValue(strdup("")); + return StringValue(""); } if (!fh.has_ecc() || !fh.has_verity()) { ErrorAbort(state, kLibfecFailure, "unable to use metadata to correct errors"); - return StringValue(strdup("")); + return StringValue(""); } fec_status status; if (!fh.get_status(status)) { ErrorAbort(state, kLibfecFailure, "failed to read FEC status"); - return StringValue(strdup("")); + return StringValue(""); } RangeSet rs; @@ -1889,8 +1856,8 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ if (fh.pread(buffer, BLOCKSIZE, (off64_t)j * BLOCKSIZE) != BLOCKSIZE) { ErrorAbort(state, kLibfecFailure, "failed to recover %s (block %zu): %s", - filename->data, j, strerror(errno)); - return StringValue(strdup("")); + filename->data.c_str(), j, strerror(errno)); + return StringValue(""); } // If we want to be able to recover from a situation where rewriting a corrected @@ -1905,8 +1872,8 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ // read and check if the errors field value has increased. } } - fprintf(stderr, "...%s image recovered successfully.\n", filename->data); - return StringValue(strdup("t")); + fprintf(stderr, "...%s image recovered successfully.\n", filename->data.c_str()); + return StringValue("t"); } void RegisterBlockImageFunctions() { diff --git a/updater/blockimg.h b/updater/include/updater/blockimg.h index 2f4ad3c04..2f4ad3c04 100644 --- a/updater/blockimg.h +++ b/updater/include/updater/blockimg.h diff --git a/updater/install.h b/updater/include/updater/install.h index 70e343404..8d6ca4728 100644 --- a/updater/install.h +++ b/updater/include/updater/install.h @@ -17,11 +17,12 @@ #ifndef _UPDATER_INSTALL_H_ #define _UPDATER_INSTALL_H_ +struct State; + void RegisterInstallFunctions(); // uiPrintf function prints msg to screen as well as logs -void uiPrintf(State* state, const char* format, ...); - -static int make_parents(char* name); +void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) + __attribute__((__format__(printf, 2, 3))); #endif diff --git a/updater/updater.h b/updater/include/updater/updater.h index d1dfdd05e..f4a2fe874 100644 --- a/updater/updater.h +++ b/updater/include/updater/updater.h @@ -18,20 +18,18 @@ #define _UPDATER_UPDATER_H_ #include <stdio.h> -#include "minzip/Zip.h" - -#include <selinux/selinux.h> -#include <selinux/label.h> +#include <ziparchive/zip_archive.h> typedef struct { FILE* cmd_pipe; - ZipArchive* package_zip; + ZipArchiveHandle package_zip; int version; uint8_t* package_zip_addr; size_t package_zip_len; } UpdaterInfo; +struct selabel_handle; extern struct selabel_handle *sehandle; #endif diff --git a/updater/install.cpp b/updater/install.cpp index 005f9f97d..a41c5db3c 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -14,53 +14,54 @@ * limitations under the License. */ +#include "updater/install.h" + #include <ctype.h> #include <errno.h> +#include <fcntl.h> +#include <ftw.h> +#include <inttypes.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/capability.h> #include <sys/mount.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <selinux/selinux.h> -#include <ftw.h> -#include <sys/capability.h> #include <sys/xattr.h> -#include <linux/xattr.h> -#include <inttypes.h> +#include <time.h> +#include <unistd.h> +#include <utime.h> #include <memory> +#include <string> #include <vector> #include <android-base/parseint.h> +#include <android-base/properties.h> #include <android-base/strings.h> #include <android-base/stringprintf.h> +#include <cutils/android_reboot.h> +#include <ext4_utils/make_ext4fs.h> +#include <ext4_utils/wipe.h> +#include <openssl/sha.h> +#include <selinux/label.h> +#include <selinux/selinux.h> +#include <ziparchive/zip_archive.h> -#include "bootloader.h" #include "applypatch/applypatch.h" -#include "cutils/android_reboot.h" -#include "cutils/misc.h" -#include "cutils/properties.h" +#include "bootloader.h" #include "edify/expr.h" #include "error_code.h" -#include "minzip/DirUtil.h" -#include "mtdutils/mounts.h" -#include "mtdutils/mtdutils.h" -#include "openssl/sha.h" +#include "mounts.h" #include "ota_io.h" -#include "updater.h" -#include "install.h" +#include "otautil/DirUtil.h" +#include "otautil/ZipUtil.h" +#include "print_sha1.h" #include "tune2fs.h" - -#ifdef USE_EXT4 -#include "make_ext4fs.h" -#include "wipe.h" -#endif +#include "updater/updater.h" // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { @@ -82,8 +83,7 @@ static void uiPrint(State* state, const std::string& buffer) { fprintf(stderr, "%s", buffer.c_str()); } -__attribute__((__format__(printf, 2, 3))) __nonnull((2)) -void uiPrintf(State* state, const char* format, ...) { +void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) { std::string error_msg; va_list ap; @@ -94,25 +94,32 @@ void uiPrintf(State* state, const char* format, ...) { uiPrint(state, error_msg); } -// Take a sha-1 digest and return it as a newly-allocated hex string. -char* PrintSha1(const uint8_t* digest) { - char* buffer = reinterpret_cast<char*>(malloc(SHA_DIGEST_LENGTH*2 + 1)); - const char* alphabet = "0123456789abcdef"; - size_t i; - for (i = 0; i < SHA_DIGEST_LENGTH; ++i) { - buffer[i*2] = alphabet[(digest[i] >> 4) & 0xf]; - buffer[i*2+1] = alphabet[digest[i] & 0xf]; - } - buffer[i*2] = '\0'; - return buffer; +// Create all parent directories of name, if necessary. +static int make_parents(char* name) { + char* p; + for (p = name + (strlen(name)-1); p > name; --p) { + if (*p != '/') continue; + *p = '\0'; + if (make_parents(name) < 0) return -1; + int result = mkdir(name, 0700); + if (result == 0) printf("created [%s]\n", name); + *p = '/'; + if (result == 0 || errno == EEXIST) { + // successfully created or already existed; we're done + return 0; + } else { + printf("failed to mkdir %s: %s\n", name, strerror(errno)); + return -1; + } + } + return 0; } // mount(fs_type, partition_type, location, mount_point) // -// fs_type="yaffs2" partition_type="MTD" location=partition // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; + char* result = nullptr; if (argc != 4 && argc != 5) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc); } @@ -171,33 +178,14 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { } } - if (strcmp(partition_type, "MTD") == 0) { - mtd_scan_partitions(); - const MtdPartition* mtd; - mtd = mtd_find_partition_by_name(location); - if (mtd == NULL) { - uiPrintf(state, "%s: no mtd partition named \"%s\"\n", - name, location); - result = strdup(""); - goto done; - } - if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { - uiPrintf(state, "mtd mount of %s failed: %s\n", - location, strerror(errno)); - result = strdup(""); - goto done; - } - result = mount_point; + if (mount(location, mount_point, fs_type, + MS_NOATIME | MS_NODEV | MS_NODIRATIME, + has_mount_options ? mount_options : "") < 0) { + uiPrintf(state, "%s: failed to mount %s at %s: %s\n", + name, location, mount_point, strerror(errno)); + result = strdup(""); } else { - if (mount(location, mount_point, fs_type, - MS_NOATIME | MS_NODEV | MS_NODIRATIME, - has_mount_options ? mount_options : "") < 0) { - uiPrintf(state, "%s: failed to mount %s at %s: %s\n", - name, location, mount_point, strerror(errno)); - result = strdup(""); - } else { - result = mount_point; - } + result = mount_point; } done: @@ -212,7 +200,7 @@ done: // is_mounted(mount_point) Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; + char* result = nullptr; if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } @@ -227,7 +215,7 @@ Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { scan_mounted_volumes(); { - const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); if (vol == NULL) { result = strdup(""); } else { @@ -242,7 +230,7 @@ done: Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; + char* result = nullptr; if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } @@ -257,7 +245,7 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { scan_mounted_volumes(); { - const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); if (vol == NULL) { uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point); result = strdup(""); @@ -293,14 +281,13 @@ static int exec_cmd(const char* path, char* const argv[]) { // format(fs_type, partition_type, location, fs_size, mount_point) // -// fs_type="yaffs2" partition_type="MTD" location=partition fs_size=<bytes> mount_point=<location> // fs_type="ext4" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location> // fs_type="f2fs" partition_type="EMMC" location=device fs_size=<bytes> mount_point=<location> // if fs_size == 0, then make fs uses the entire partition. // if fs_size > 0, that is the size to use // if fs_size < 0, then reserve that many bytes at the end of the partition (not for "f2fs") Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; + char* result = nullptr; if (argc != 5) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc); } @@ -334,35 +321,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } - if (strcmp(partition_type, "MTD") == 0) { - mtd_scan_partitions(); - const MtdPartition* mtd = mtd_find_partition_by_name(location); - if (mtd == NULL) { - printf("%s: no mtd partition named \"%s\"", - name, location); - result = strdup(""); - goto done; - } - MtdWriteContext* ctx = mtd_write_partition(mtd); - if (ctx == NULL) { - printf("%s: can't write \"%s\"", name, location); - result = strdup(""); - goto done; - } - if (mtd_erase_blocks(ctx, -1) == -1) { - mtd_write_close(ctx); - printf("%s: failed to erase \"%s\"", name, location); - result = strdup(""); - goto done; - } - if (mtd_write_close(ctx) != 0) { - printf("%s: failed to close \"%s\"", name, location); - result = strdup(""); - goto done; - } - result = location; -#ifdef USE_EXT4 - } else if (strcmp(fs_type, "ext4") == 0) { + if (strcmp(fs_type, "ext4") == 0) { int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); if (status != 0) { printf("%s: make_ext4fs failed (%d) on %s", @@ -389,7 +348,6 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } result = location; -#endif } else { printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", name, fs_type, partition_type); @@ -403,7 +361,7 @@ done: } Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; + char* result = nullptr; if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } @@ -442,15 +400,10 @@ done: } Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { - char** paths = reinterpret_cast<char**>(malloc(argc * sizeof(char*))); + std::vector<std::string> paths; for (int i = 0; i < argc; ++i) { - paths[i] = Evaluate(state, argv[i]); - if (paths[i] == NULL) { - for (int j = 0; j < i; ++j) { - free(paths[j]); - } - free(paths); - return NULL; + if (!Evaluate(state, argv[i], &paths[i])) { + return nullptr; } } @@ -458,15 +411,12 @@ Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { int success = 0; for (int i = 0; i < argc; ++i) { - if ((recursive ? dirUnlinkHierarchy(paths[i]) : unlink(paths[i])) == 0) + if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { ++success; - free(paths[i]); + } } - free(paths); - char buffer[10]; - sprintf(buffer, "%d", success); - return StringValue(strdup(buffer)); + return StringValue(android::base::StringPrintf("%d", success)); } @@ -518,17 +468,16 @@ Value* PackageExtractDirFn(const char* name, State* state, char* dest_path; if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; - ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; + ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; // To create a consistent system image, never use the clock for timestamps. struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default - bool success = mzExtractRecursive(za, zip_path, dest_path, - ×tamp, - NULL, NULL, sehandle); + bool success = ExtractPackageRecursive(za, zip_path, dest_path, ×tamp, sehandle); + free(zip_path); free(dest_path); - return StringValue(strdup(success ? "t" : "")); + return StringValue(success ? "t" : ""); } @@ -548,26 +497,27 @@ Value* PackageExtractFileFn(const char* name, State* state, if (argc == 2) { // The two-argument version extracts to a file. - ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; + ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; char* zip_path; char* dest_path; if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; - const ZipEntry* entry = mzFindZipEntry(za, zip_path); - if (entry == NULL) { + ZipString zip_string_path(zip_path); + ZipEntry entry; + if (FindEntry(za, zip_string_path, &entry) != 0) { printf("%s: no %s in package\n", name, zip_path); goto done2; } { - int fd = TEMP_FAILURE_RETRY(ota_open(dest_path, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, + int fd = TEMP_FAILURE_RETRY(ota_open(dest_path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); if (fd == -1) { printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno)); goto done2; } - success = mzExtractZipEntryToFile(za, entry, fd); + success = ExtractEntryToFile(za, &entry, fd); if (ota_fsync(fd) == -1) { printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno)); success = false; @@ -581,7 +531,7 @@ Value* PackageExtractFileFn(const char* name, State* state, done2: free(zip_path); free(dest_path); - return StringValue(strdup(success ? "t" : "")); + return StringValue(success ? "t" : ""); } else { // The one-argument version returns the contents of the file // as the result. @@ -589,59 +539,33 @@ Value* PackageExtractFileFn(const char* name, State* state, char* zip_path; if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; - Value* v = reinterpret_cast<Value*>(malloc(sizeof(Value))); - v->type = VAL_BLOB; - v->size = -1; - v->data = NULL; + Value* v = new Value(VAL_INVALID, ""); - ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; - const ZipEntry* entry = mzFindZipEntry(za, zip_path); - if (entry == NULL) { + ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; + ZipString zip_string_path(zip_path); + ZipEntry entry; + if (FindEntry(za, zip_string_path, &entry) != 0) { printf("%s: no %s in package\n", name, zip_path); goto done1; } - v->size = mzGetZipEntryUncompLen(entry); - v->data = reinterpret_cast<char*>(malloc(v->size)); - if (v->data == NULL) { - printf("%s: failed to allocate %ld bytes for %s\n", - name, (long)v->size, zip_path); - goto done1; + v->data.resize(entry.uncompressed_length); + if (ExtractToMemory(za, &entry, reinterpret_cast<uint8_t*>(&v->data[0]), + v->data.size()) != 0) { + printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size()); + } else { + success = true; } - success = mzExtractZipEntryToBuffer(za, entry, - (unsigned char *)v->data); - done1: free(zip_path); if (!success) { - free(v->data); - v->data = NULL; - v->size = -1; - } - return v; - } -} - -// Create all parent directories of name, if necessary. -static int make_parents(char* name) { - char* p; - for (p = name + (strlen(name)-1); p > name; --p) { - if (*p != '/') continue; - *p = '\0'; - if (make_parents(name) < 0) return -1; - int result = mkdir(name, 0700); - if (result == 0) printf("created [%s]\n", name); - *p = '/'; - if (result == 0 || errno == EEXIST) { - // successfully created or already existed; we're done - return 0; + v->data.clear(); } else { - printf("failed to mkdir %s: %s\n", name, strerror(errno)); - return -1; + v->type = VAL_BLOB; } + return v; } - return 0; } // symlink target src1 src2 ... @@ -650,13 +574,13 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc == 0) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc); } - char* target; - target = Evaluate(state, argv[0]); - if (target == NULL) return NULL; + std::string target; + if (!Evaluate(state, argv[0], &target)) { + return nullptr; + } char** srcs = ReadVarArgs(state, argc-1, argv+1); if (srcs == NULL) { - free(target); return NULL; } @@ -672,12 +596,12 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { } if (make_parents(srcs[i])) { printf("%s: failed to symlink %s to %s: making parents failed\n", - name, srcs[i], target); + name, srcs[i], target.c_str()); ++bad; } - if (symlink(target, srcs[i]) < 0) { + if (symlink(target.c_str(), srcs[i]) < 0) { printf("%s: failed to symlink %s to %s: %s\n", - name, srcs[i], target, strerror(errno)); + name, srcs[i], target.c_str(), strerror(errno)); ++bad; } free(srcs[i]); @@ -686,7 +610,7 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { if (bad) { return ErrorAbort(state, kSymlinkFailure, "%s: some symlinks failed", name); } - return StringValue(strdup("")); + return StringValue(""); } struct perm_parsed_args { @@ -949,21 +873,20 @@ done: return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); } - return StringValue(strdup("")); + return StringValue(""); } Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } - char* key = Evaluate(state, argv[0]); - if (key == NULL) return NULL; - - char value[PROPERTY_VALUE_MAX]; - property_get(key, value, ""); - free(key); + std::string key; + if (!Evaluate(state, argv[0], &key)) { + return nullptr; + } + std::string value = android::base::GetProperty(key, ""); - return StringValue(strdup(value)); + return StringValue(value); } @@ -998,13 +921,13 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { buffer = reinterpret_cast<char*>(malloc(st.st_size+1)); if (buffer == NULL) { - ErrorAbort(state, kFileGetPropFailure, "%s: failed to alloc %lld bytes", name, - (long long)st.st_size+1); + ErrorAbort(state, kFileGetPropFailure, "%s: failed to alloc %zu bytes", name, + static_cast<size_t>(st.st_size+1)); goto done; } FILE* f; - f = fopen(filename, "rb"); + f = ota_fopen(filename, "rb"); if (f == NULL) { ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename, strerror(errno)); @@ -1012,14 +935,14 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } if (ota_fread(buffer, 1, st.st_size, f) != static_cast<size_t>(st.st_size)) { - ErrorAbort(state, kFreadFailure, "%s: failed to read %lld bytes from %s", - name, (long long)st.st_size+1, filename); - fclose(f); + ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", + name, static_cast<size_t>(st.st_size), filename); + ota_fclose(f); goto done; } buffer[st.st_size] = '\0'; - fclose(f); + ota_fclose(f); char* line; line = strtok(buffer, "\n"); @@ -1066,98 +989,6 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(result); } -// write_raw_image(filename_or_blob, partition) -Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; - - Value* partition_value; - Value* contents; - if (ReadValueArgs(state, argv, 2, &contents, &partition_value) < 0) { - return NULL; - } - - char* partition = NULL; - if (partition_value->type != VAL_STRING) { - ErrorAbort(state, kArgsParsingFailure, "partition argument to %s must be string", name); - goto done; - } - partition = partition_value->data; - if (strlen(partition) == 0) { - ErrorAbort(state, kArgsParsingFailure, "partition argument to %s can't be empty", name); - goto done; - } - if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { - ErrorAbort(state, kArgsParsingFailure, "file argument to %s can't be empty", name); - goto done; - } - - mtd_scan_partitions(); - const MtdPartition* mtd; - mtd = mtd_find_partition_by_name(partition); - if (mtd == NULL) { - printf("%s: no mtd partition named \"%s\"\n", name, partition); - result = strdup(""); - goto done; - } - - MtdWriteContext* ctx; - ctx = mtd_write_partition(mtd); - if (ctx == NULL) { - printf("%s: can't write mtd partition \"%s\"\n", - name, partition); - result = strdup(""); - goto done; - } - - bool success; - - if (contents->type == VAL_STRING) { - // we're given a filename as the contents - char* filename = contents->data; - FILE* f = ota_fopen(filename, "rb"); - if (f == NULL) { - printf("%s: can't open %s: %s\n", name, filename, strerror(errno)); - result = strdup(""); - goto done; - } - - success = true; - char* buffer = reinterpret_cast<char*>(malloc(BUFSIZ)); - int read; - while (success && (read = ota_fread(buffer, 1, BUFSIZ, f)) > 0) { - int wrote = mtd_write_data(ctx, buffer, read); - success = success && (wrote == read); - } - free(buffer); - ota_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) { - printf("mtd_write_data to %s failed: %s\n", - partition, strerror(errno)); - } - - if (mtd_erase_blocks(ctx, -1) == -1) { - printf("%s: error erasing blocks of %s\n", name, partition); - } - if (mtd_write_close(ctx) != 0) { - printf("%s: error closing write of %s\n", name, partition); - } - - printf("%s %s partition\n", - success ? "wrote" : "failed to write", partition); - - result = success ? partition : strdup(""); - -done: - if (result != partition) FreeValue(partition_value); - FreeValue(contents); - return StringValue(result); -} - // apply_patch_space(bytes) Value* ApplyPatchSpaceFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1174,7 +1005,7 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, return nullptr; } - return StringValue(strdup(CacheSizeCheck(bytes) ? "" : "t")); + return StringValue(CacheSizeCheck(bytes) ? "" : "t"); } // apply_patch(file, size, init_sha1, tgt_sha1, patch) @@ -1206,17 +1037,16 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } int patchcount = (argc-4) / 2; - std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc-4, argv+4), - free); + std::unique_ptr<Value*> arg_values(ReadValueVarArgs(state, argc-4, argv+4)); if (!arg_values) { return nullptr; } - std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patch_shas; - std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> patches; + std::vector<std::unique_ptr<Value>> patch_shas; + std::vector<std::unique_ptr<Value>> patches; // Protect values by unique_ptrs first to get rid of memory leak. for (int i = 0; i < patchcount * 2; i += 2) { - patch_shas.emplace_back(arg_values.get()[i], FreeValue); - patches.emplace_back(arg_values.get()[i+1], FreeValue); + patch_shas.emplace_back(arg_values.get()[i]); + patches.emplace_back(arg_values.get()[i+1]); } for (int i = 0; i < patchcount; ++i) { @@ -1230,7 +1060,7 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } } - std::vector<char*> patch_sha_str; + std::vector<std::string> patch_sha_str; std::vector<Value*> patch_ptrs; for (int i = 0; i < patchcount; ++i) { patch_sha_str.push_back(patch_shas[i]->data); @@ -1239,9 +1069,9 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { int result = applypatch(source_filename, target_filename, target_sha1, target_size, - patchcount, patch_sha_str.data(), patch_ptrs.data(), NULL); + patch_sha_str, patch_ptrs.data(), NULL); - return StringValue(strdup(result == 0 ? "t" : "")); + return StringValue(result == 0 ? "t" : ""); } // apply_patch_check(file, [sha1_1, ...]) @@ -1254,21 +1084,17 @@ Value* ApplyPatchCheckFn(const char* name, State* state, char* filename; if (ReadArgs(state, argv, 1, &filename) < 0) { - return NULL; + return nullptr; } - int patchcount = argc-1; - char** sha1s = ReadVarArgs(state, argc-1, argv+1); - - int result = applypatch_check(filename, patchcount, sha1s); - - int i; - for (i = 0; i < patchcount; ++i) { - free(sha1s[i]); + std::vector<std::string> sha1s; + if (!ReadArgs(state, argc-1, argv+1, &sha1s)) { + return nullptr; } - free(sha1s); - return StringValue(strdup(result == 0 ? "t" : "")); + int result = applypatch_check(filename, sha1s); + + return StringValue(result == 0 ? "t" : ""); } // This is the updater side handler for ui_print() in edify script. Contents @@ -1288,7 +1114,7 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { buffer += "\n"; uiPrint(state, buffer); - return StringValue(strdup(buffer.c_str())); + return StringValue(buffer); } Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1296,7 +1122,7 @@ Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); } fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n"); - return StringValue(strdup("t")); + return StringValue("t"); } Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1339,10 +1165,7 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { free(args); free(args2); - char buffer[20]; - sprintf(buffer, "%d", status); - - return StringValue(strdup(buffer)); + return StringValue(android::base::StringPrintf("%d", status)); } // sha1_check(data) @@ -1358,45 +1181,40 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); } - std::unique_ptr<Value*, decltype(&free)> arg_values(ReadValueVarArgs(state, argc, argv), free); + std::unique_ptr<Value*> arg_values(ReadValueVarArgs(state, argc, argv)); if (arg_values == nullptr) { return nullptr; } - std::vector<std::unique_ptr<Value, decltype(&FreeValue)>> args; + std::vector<std::unique_ptr<Value>> args; for (int i = 0; i < argc; ++i) { - args.emplace_back(arg_values.get()[i], FreeValue); + args.emplace_back(arg_values.get()[i]); } - if (args[0]->size < 0) { - return StringValue(strdup("")); + if (args[0]->type == VAL_INVALID) { + return StringValue(""); } uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast<uint8_t*>(args[0]->data), args[0]->size, digest); + SHA1(reinterpret_cast<const uint8_t*>(args[0]->data.c_str()), args[0]->data.size(), digest); if (argc == 1) { - return StringValue(PrintSha1(digest)); + return StringValue(print_sha1(digest)); } - int i; - uint8_t arg_digest[SHA_DIGEST_LENGTH]; - for (i = 1; i < argc; ++i) { + for (int i = 1; i < argc; ++i) { + uint8_t arg_digest[SHA_DIGEST_LENGTH]; if (args[i]->type != VAL_STRING) { - printf("%s(): arg %d is not a string; skipping", - name, i); - } else if (ParseSha1(args[i]->data, arg_digest) != 0) { + printf("%s(): arg %d is not a string; skipping", name, i); + } else if (ParseSha1(args[i]->data.c_str(), arg_digest) != 0) { // Warn about bad args and skip them. - printf("%s(): error parsing \"%s\" as sha-1; skipping", - name, args[i]->data); + printf("%s(): error parsing \"%s\" as sha-1; skipping", name, args[i]->data.c_str()); } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) { - break; + // Found a match. + return args[i].release(); } } - if (i >= argc) { - // Didn't match any of the hex strings; return false. - return StringValue(strdup("")); - } - // Found a match. - return args[i].release(); + + // Didn't match any of the hex strings; return false. + return StringValue(""); } // Read a local file and return its contents (the Value* returned @@ -1408,21 +1226,12 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { char* filename; if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; - Value* v = static_cast<Value*>(malloc(sizeof(Value))); - if (v == nullptr) { - return nullptr; - } - v->type = VAL_BLOB; - v->size = -1; - v->data = nullptr; + Value* v = new Value(VAL_INVALID, ""); FileContents fc; if (LoadFileContents(filename, &fc) == 0) { - v->data = static_cast<char*>(malloc(fc.data.size())); - if (v->data != nullptr) { - memcpy(v->data, fc.data.data(), fc.data.size()); - v->size = fc.data.size(); - } + v->type = VAL_BLOB; + v->data = std::string(fc.data.begin(), fc.data.end()); } free(filename); return v; @@ -1446,22 +1255,18 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { char* property; if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL; - char buffer[80]; - // zero out the 'command' field of the bootloader message. + char buffer[80]; memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command)); - FILE* f = fopen(filename, "r+b"); + FILE* f = ota_fopen(filename, "r+b"); fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); - fclose(f); + ota_fclose(f); free(filename); - strcpy(buffer, "reboot,"); - if (property != NULL) { - strncat(buffer, property, sizeof(buffer)-10); - } - - property_set(ANDROID_RB_PROPERTY, buffer); + std::string reboot_cmd = "reboot,"; + if (property != nullptr) reboot_cmd += property; + android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd); sleep(5); free(property); @@ -1492,18 +1297,21 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { // bootloader message that the main recovery uses to save its // arguments in case of the device restarting midway through // package installation. - FILE* f = fopen(filename, "r+b"); + FILE* f = ota_fopen(filename, "r+b"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - int to_write = strlen(stagestr)+1; - int max_size = sizeof(((struct bootloader_message*)0)->stage); + size_t to_write = strlen(stagestr) + 1; + size_t max_size = sizeof(((struct bootloader_message*)0)->stage); if (to_write > max_size) { to_write = max_size; - stagestr[max_size-1] = 0; + stagestr[max_size - 1] = 0; } - ota_fwrite(stagestr, to_write, 1, f); - fclose(f); + size_t status = ota_fwrite(stagestr, to_write, 1, f); + ota_fclose(f); free(stagestr); + if (status != to_write) { + return StringValue(""); + } return StringValue(filename); } @@ -1518,13 +1326,16 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; char buffer[sizeof(((struct bootloader_message*)0)->stage)]; - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - ota_fread(buffer, sizeof(buffer), 1, f); - fclose(f); - buffer[sizeof(buffer)-1] = '\0'; + size_t status = ota_fread(buffer, sizeof(buffer), 1, f); + ota_fclose(f); + if (status != sizeof(buffer)) { + return StringValue(""); + } - return StringValue(strdup(buffer)); + buffer[sizeof(buffer)-1] = '\0'; + return StringValue(buffer); } Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1546,7 +1357,7 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) ota_close(fd); - return StringValue(strdup(success ? "t" : "")); + return StringValue(success ? "t" : ""); } Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1555,7 +1366,7 @@ Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { } UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); fprintf(ui->cmd_pipe, "enable_reboot\n"); - return StringValue(strdup("t")); + return StringValue("t"); } Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1586,7 +1397,7 @@ Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result); } - return StringValue(strdup("t")); + return StringValue("t"); } void RegisterInstallFunctions() { @@ -1616,7 +1427,6 @@ void RegisterInstallFunctions() { RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); - RegisterFunction("write_raw_image", WriteRawImageFn); RegisterFunction("apply_patch", ApplyPatchFn); RegisterFunction("apply_patch_check", ApplyPatchCheckFn); diff --git a/updater/updater.cpp b/updater/updater.cpp index e956dd557..7327c52e3 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -14,18 +14,26 @@ * limitations under the License. */ +#include "updater/updater.h" + #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> -#include "edify/expr.h" -#include "updater.h" -#include "install.h" -#include "blockimg.h" -#include "minzip/Zip.h" -#include "minzip/SysUtil.h" +#include <string> + +#include <android-base/strings.h> +#include <selinux/label.h> +#include <selinux/selinux.h> +#include <ziparchive/zip_archive.h> + #include "config.h" +#include "edify/expr.h" +#include "otautil/DirUtil.h" +#include "otautil/SysUtil.h" +#include "updater/blockimg.h" +#include "updater/install.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -77,28 +85,35 @@ int main(int argc, char** argv) { printf("failed to map package %s\n", argv[3]); return 3; } - ZipArchive za; - int err; - err = mzOpenZipArchive(map.addr, map.length, &za); - if (err != 0) { + ZipArchiveHandle za; + int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za); + if (open_err != 0) { printf("failed to open package %s: %s\n", - argv[3], strerror(err)); + argv[3], ErrorCodeString(open_err)); + CloseArchive(za); return 3; } - ota_io_init(&za); - - const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); - if (script_entry == NULL) { - printf("failed to find %s in %s\n", SCRIPT_NAME, package_filename); + ota_io_init(za); + + ZipString script_name(SCRIPT_NAME); + ZipEntry script_entry; + int find_err = FindEntry(za, script_name, &script_entry); + if (find_err != 0) { + printf("failed to find %s in %s: %s\n", SCRIPT_NAME, package_filename, + ErrorCodeString(find_err)); + CloseArchive(za); return 4; } - char* script = reinterpret_cast<char*>(malloc(script_entry->uncompLen+1)); - if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { - printf("failed to read script from package\n"); + std::string script; + script.resize(script_entry.uncompressed_length); + int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast<uint8_t*>(&script[0]), + script_entry.uncompressed_length); + if (extract_err != 0) { + printf("failed to read script from package: %s\n", ErrorCodeString(extract_err)); + CloseArchive(za); return 5; } - script[script_entry->uncompLen] = '\0'; // Configure edify's functions. @@ -106,15 +121,15 @@ int main(int argc, char** argv) { RegisterInstallFunctions(); RegisterBlockImageFunctions(); RegisterDeviceExtensions(); - FinishRegistration(); // Parse the script. Expr* root; int error_count = 0; - int error = parse_string(script, &root, &error_count); + int error = parse_string(script.c_str(), &root, &error_count); if (error != 0 || error_count > 0) { printf("%d parse errors\n", error_count); + CloseArchive(za); return 6; } @@ -132,15 +147,12 @@ int main(int argc, char** argv) { UpdaterInfo updater_info; updater_info.cmd_pipe = cmd_pipe; - updater_info.package_zip = &za; + updater_info.package_zip = za; updater_info.version = atoi(version); updater_info.package_zip_addr = map.addr; updater_info.package_zip_len = map.length; - State state; - state.cookie = &updater_info; - state.script = script; - state.errmsg = NULL; + State state(script, &updater_info); if (argc == 5) { if (strcmp(argv[4], "retry") == 0) { @@ -150,29 +162,29 @@ int main(int argc, char** argv) { } } - char* result = Evaluate(&state, root); + std::string result; + bool status = Evaluate(&state, root, &result); if (have_eio_error) { fprintf(cmd_pipe, "retry_update\n"); } - if (result == NULL) { - if (state.errmsg == NULL) { + if (!status) { + if (state.errmsg.empty()) { printf("script aborted (no error message)\n"); fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); } else { - printf("script aborted: %s\n", state.errmsg); - char* line = strtok(state.errmsg, "\n"); - while (line) { + printf("script aborted: %s\n", state.errmsg.c_str()); + const std::vector<std::string> lines = android::base::Split(state.errmsg, "\n"); + for (const std::string& line : lines) { // Parse the error code in abort message. // Example: "E30: This package is for bullhead devices." - if (*line == 'E') { - if (sscanf(line, "E%u: ", &state.error_code) != 1) { - printf("Failed to parse error code: [%s]\n", line); + if (!line.empty() && line[0] == 'E') { + if (sscanf(line.c_str(), "E%u: ", &state.error_code) != 1) { + printf("Failed to parse error code: [%s]\n", line.c_str()); } } - fprintf(cmd_pipe, "ui_print %s\n", line); - line = strtok(NULL, "\n"); + fprintf(cmd_pipe, "ui_print %s\n", line.c_str()); } fprintf(cmd_pipe, "ui_print\n"); } @@ -186,18 +198,18 @@ int main(int argc, char** argv) { } } - free(state.errmsg); + if (updater_info.package_zip) { + CloseArchive(updater_info.package_zip); + } return 7; } else { - fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); - free(result); + fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str()); } if (updater_info.package_zip) { - mzCloseZipArchive(updater_info.package_zip); + CloseArchive(updater_info.package_zip); } sysReleaseMap(&map); - free(script); return 0; } |