From a7b9a4660c18a88413280c84c03917ae953d62b0 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: IO fault injection for OTA packages Bug: 25951086 Change-Id: I31c74c735eb7a975b7f41fe2b2eff042e5699c0c (cherry-picked from commit f1fc48c6e62cfee42d25ad12f443e22d50c15d0b) --- updater/Android.mk | 2 +- updater/blockimg.cpp | 25 +++++++++++++------------ updater/install.cpp | 43 ++++++++++++++++++++++--------------------- 3 files changed, 36 insertions(+), 34 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 6fdd30895..d7aa613e9 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -45,7 +45,7 @@ LOCAL_STATIC_LIBRARIES += \ endif LOCAL_STATIC_LIBRARIES += $(TARGET_RECOVERY_UPDATER_LIBS) $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) -LOCAL_STATIC_LIBRARIES += libapplypatch libbase libedify libmtdutils libminzip libz +LOCAL_STATIC_LIBRARIES += libapplypatch libbase libotafault libedify libmtdutils libminzip libz LOCAL_STATIC_LIBRARIES += libbz LOCAL_STATIC_LIBRARIES += libcutils liblog libc LOCAL_STATIC_LIBRARIES += libselinux diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 6e056006c..44de4e031 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,6 +45,7 @@ #include "install.h" #include "openssl/sha.h" #include "minzip/Hash.h" +#include "otafault/ota_io.h" #include "print_sha1.h" #include "unique_fd.h" #include "updater.h" @@ -139,7 +140,7 @@ static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) { static int read_all(int fd, uint8_t* data, size_t size) { size_t so_far = 0; while (so_far < size) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, data+so_far, size-so_far)); + ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far)); if (r == -1) { fprintf(stderr, "read failed: %s\n", strerror(errno)); return -1; @@ -156,7 +157,7 @@ static int read_all(int fd, std::vector& buffer, size_t size) { static int write_all(int fd, const uint8_t* data, size_t size) { size_t written = 0; while (written < size) { - ssize_t w = TEMP_FAILURE_RETRY(write(fd, data+written, size-written)); + ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written)); if (w == -1) { fprintf(stderr, "write failed: %s\n", strerror(errno)); return -1; @@ -553,7 +554,7 @@ static int LoadStash(const std::string& base, const std::string& id, bool verify return -1; } - int fd = TEMP_FAILURE_RETRY(open(fn.c_str(), O_RDONLY)); + int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_RDONLY)); unique_fd fd_holder(fd); if (fd == -1) { @@ -610,7 +611,7 @@ 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)); + int fd = TEMP_FAILURE_RETRY(ota_open(fn.c_str(), O_WRONLY | O_CREAT | O_TRUNC, STASH_FILE_MODE)); unique_fd fd_holder(fd); if (fd == -1) { @@ -622,7 +623,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks return -1; } - if (fsync(fd) == -1) { + if (ota_fsync(fd) == -1) { fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); return -1; } @@ -634,7 +635,7 @@ 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)); + int dfd = TEMP_FAILURE_RETRY(ota_open(dname.c_str(), O_RDONLY | O_DIRECTORY)); unique_fd dfd_holder(dfd); if (dfd == -1) { @@ -642,7 +643,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks return -1; } - if (fsync(dfd) == -1) { + if (ota_fsync(dfd) == -1) { fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); return -1; } @@ -1346,7 +1347,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg return StringValue(strdup("")); } - params.fd = TEMP_FAILURE_RETRY(open(blockdev_filename->data, O_RDWR)); + params.fd = TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR)); unique_fd fd_holder(params.fd); if (params.fd == -1) { @@ -1465,7 +1466,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg } if (params.canwrite) { - if (fsync(params.fd) == -1) { + if (ota_fsync(params.fd) == -1) { fprintf(stderr, "fsync failed: %s\n", strerror(errno)); goto pbiudone; } @@ -1490,7 +1491,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg rc = 0; pbiudone: - if (fsync(params.fd) == -1) { + if (ota_fsync(params.fd) == -1) { fprintf(stderr, "fsync failed: %s\n", strerror(errno)); } // params.fd will be automatically closed because of the fd_holder above. @@ -1614,7 +1615,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) return StringValue(strdup("")); } - int fd = open(blockdev_filename->data, O_RDWR); + int fd = ota_open(blockdev_filename->data, O_RDWR); unique_fd fd_holder(fd); if (fd < 0) { ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno)); @@ -1668,7 +1669,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) return StringValue(strdup("")); } - int fd = open(arg_filename->data, O_RDONLY); + int fd = ota_open(arg_filename->data, O_RDONLY); unique_fd fd_holder(fd); if (fd == -1) { ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno)); diff --git a/updater/install.cpp b/updater/install.cpp index 45bbf2bc1..1cd9a5690 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -51,6 +51,7 @@ #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" +#include "otafault/ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" @@ -557,18 +558,18 @@ Value* PackageExtractFileFn(const char* name, State* state, } { - int fd = TEMP_FAILURE_RETRY(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 | O_SYNC, 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); - if (fsync(fd) == -1) { + if (ota_fsync(fd) == -1) { printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno)); success = false; } - if (close(fd) == -1) { + if (ota_close(fd) == -1) { printf("close of \"%s\" failed: %s\n", dest_path, strerror(errno)); success = false; } @@ -995,21 +996,21 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } FILE* f; - f = fopen(filename, "rb"); + f = ota_fopen(filename, "rb"); if (f == NULL) { ErrorAbort(state, "%s: failed to open %s: %s", name, filename, strerror(errno)); goto done; } - if (fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { + if (ota_fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { ErrorAbort(state, "%s: failed to read %lld bytes from %s", name, (long long)st.st_size+1, filename); - fclose(f); + ota_fclose(f); goto done; } buffer[st.st_size] = '\0'; - fclose(f); + ota_fclose(f); char* line; line = strtok(buffer, "\n"); @@ -1104,7 +1105,7 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { if (contents->type == VAL_STRING) { // we're given a filename as the contents char* filename = contents->data; - FILE* f = fopen(filename, "rb"); + FILE* f = ota_fopen(filename, "rb"); if (f == NULL) { printf("%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); @@ -1114,12 +1115,12 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { success = true; char* buffer = reinterpret_cast(malloc(BUFSIZ)); int read; - while (success && (read = fread(buffer, 1, BUFSIZ, f)) > 0) { + while (success && (read = ota_fread(buffer, 1, BUFSIZ, f)) > 0) { int wrote = mtd_write_data(ctx, buffer, read); success = success && (wrote == read); } free(buffer); - fclose(f); + ota_fclose(f); } else { // we're given a blob as the contents ssize_t wrote = mtd_write_data(ctx, contents->data, contents->size); @@ -1438,10 +1439,10 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { // zero out the 'command' field of the bootloader message. 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); - fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); - fclose(f); + ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); + ota_fclose(f); free(filename); strcpy(buffer, "reboot,"); @@ -1480,7 +1481,7 @@ 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); @@ -1488,8 +1489,8 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { to_write = max_size; stagestr[max_size-1] = 0; } - fwrite(stagestr, to_write, 1, f); - fclose(f); + ota_fwrite(stagestr, to_write, 1, f); + ota_fclose(f); free(stagestr); return StringValue(filename); @@ -1506,10 +1507,10 @@ 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); - fread(buffer, sizeof(buffer), 1, f); - fclose(f); + ota_fread(buffer, sizeof(buffer), 1, f); + ota_fclose(f); buffer[sizeof(buffer)-1] = '\0'; return StringValue(strdup(buffer)); @@ -1526,13 +1527,13 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) size_t len; android::base::ParseUint(len_str, &len); - int fd = open(filename, O_WRONLY, 0644); + int fd = ota_open(filename, O_WRONLY, 0644); int success = wipe_block_device(fd, len); free(filename); free(len_str); - close(fd); + ota_close(fd); return StringValue(strdup(success ? "t" : "")); } -- cgit v1.2.3 From d6c93afcc28cc65217ba65eeb646009c4f15a2ad Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Wed, 10 Feb 2016 16:41:10 -0800 Subject: applypatch: use vector to store data in FileContents. Bug: 26906416 Change-Id: Ib53b445cd415a1ed5e95733fbc4073f9ef4dbc43 --- updater/install.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 1cd9a5690..413e147a1 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1398,21 +1398,22 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { char* filename; if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; - Value* v = reinterpret_cast(malloc(sizeof(Value))); + Value* v = static_cast(malloc(sizeof(Value))); + if (v == nullptr) { + return nullptr; + } v->type = VAL_BLOB; + v->size = -1; + v->data = nullptr; FileContents fc; if (LoadFileContents(filename, &fc) != 0) { - free(filename); - v->size = -1; - v->data = NULL; - free(fc.data); - return v; + v->data = static_cast(malloc(fc.data.size())); + if (v->data != nullptr) { + memcpy(v->data, fc.data.data(), fc.data.size()); + v->size = fc.data.size(); + } } - - v->size = fc.size; - v->data = (char*)fc.data; - free(filename); return v; } -- cgit v1.2.3 From 39c1b5e8722dbf0bbb3ee45e201373099f075345 Mon Sep 17 00:00:00 2001 From: Jed Estep Date: Tue, 15 Dec 2015 16:04:53 -0800 Subject: Control fault injection with config files instead of build flags Bug: 26570379 Change-Id: I76109d09276d6e3ed3a32b6fedafb2582f545c0c (cherry picked from commit d940887dde23597dc358b16d96ca48dd7480fee6) --- updater/blockimg.cpp | 2 +- updater/install.cpp | 2 +- updater/updater.cpp | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 44de4e031..56378d4f5 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,7 +45,7 @@ #include "install.h" #include "openssl/sha.h" #include "minzip/Hash.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "print_sha1.h" #include "unique_fd.h" #include "updater.h" diff --git a/updater/install.cpp b/updater/install.cpp index 413e147a1..bc4cca913 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -51,7 +51,7 @@ #include "minzip/DirUtil.h" #include "mtdutils/mounts.h" #include "mtdutils/mtdutils.h" -#include "otafault/ota_io.h" +#include "ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" diff --git a/updater/updater.cpp b/updater/updater.cpp index 0f22e6d04..efb4a8cec 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -25,6 +25,7 @@ #include "blockimg.h" #include "minzip/Zip.h" #include "minzip/SysUtil.h" +#include "config.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -82,6 +83,7 @@ int main(int argc, char** argv) { argv[3], strerror(err)); return 3; } + ota_io_init(&za); const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { -- cgit v1.2.3 From 3c62b67faf8a25f1dd1c44dc19759c3997fdfd36 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Feb 2016 18:25:58 -0800 Subject: Reboot and retry on I/O errors When I/O error happens, reboot and retry installation two times before we abort this OTA update. Bug: 25633753 Change-Id: Iba6d4203a343a725aa625a41d237606980d62f69 --- updater/updater.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index efb4a8cec..1693fa1db 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -36,6 +36,8 @@ // (Note it's "updateR-script", not the older "update-script".) #define SCRIPT_NAME "META-INF/com/google/android/updater-script" +extern bool have_eio_error; + struct selabel_handle *sehandle; int main(int argc, char** argv) { @@ -141,6 +143,11 @@ int main(int argc, char** argv) { state.errmsg = NULL; char* result = Evaluate(&state, root); + + if (have_eio_error) { + fprintf(cmd_pipe, "retry_update\n"); + } + if (result == NULL) { if (state.errmsg == NULL) { printf("script aborted (no error message)\n"); -- cgit v1.2.3 From d80a99883d5ae2b117c54f076fe1df7eae86d2f8 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Mar 2016 11:43:47 -0800 Subject: Fix the improper use of LOCAL_WHOLE_STATIC_LIBRARIES. If two libraries both use LOCAL_WHOLE_STATIC_LIBRARIES and include a same library, there would be linking errors when generating a shared library (or executable) that depends on the two libraries both. Also clean up Android.mk files. Remove the "LOCAL_MODULE_TAGS := eng" line for the updater module. The module will then default to "optional" which won't be built until needed. Change-Id: I3ec227109b8aa744b7568e7f82f575aae3fe0e6f --- updater/Android.mk | 66 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 28 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index d7aa613e9..47c56ccd9 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -14,26 +14,50 @@ LOCAL_PATH := $(call my-dir) -updater_src_files := \ - install.cpp \ - blockimg.cpp \ - updater.cpp - -# -# Build a statically-linked binary to include in OTA packages -# +# updater (static executable) +# =============================== +# Build a statically-linked binary to include in OTA packages. 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 +updater_src_files := \ + install.cpp \ + blockimg.cpp \ + updater.cpp LOCAL_CLANG := true - LOCAL_SRC_FILES := $(updater_src_files) -LOCAL_STATIC_LIBRARIES += libfec libfec_rs libext4_utils_static libsquashfs_utils libcrypto_static +LOCAL_STATIC_LIBRARIES += \ + $(TARGET_RECOVERY_UPDATER_LIBS) \ + $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \ + libfec \ + libfec_rs \ + libext4_utils_static \ + libsquashfs_utils \ + libcrypto_static \ + libapplypatch \ + libbase \ + libotafault \ + libedify \ + libmtdutils \ + libminzip \ + libz \ + libbz \ + libcutils \ + liblog \ + libselinux + +tune2fs_static_libraries := \ + libext2_com_err \ + libext2_blkid \ + libext2_quota \ + libext2_uuid_static \ + libext2_e2p \ + libext2fs + +LOCAL_STATIC_LIBRARIES += \ + libtune2fs \ + $(tune2fs_static_libraries) ifeq ($(TARGET_USERIMAGES_USE_EXT4), true) LOCAL_CFLAGS += -DUSE_EXT4 @@ -44,20 +68,6 @@ LOCAL_STATIC_LIBRARIES += \ 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_C_INCLUDES += external/e2fsprogs/misc LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. -- cgit v1.2.3 From 7eca97e75df5d152730a7faad78e13fe741bc4d2 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 22 Mar 2016 18:08:12 -0700 Subject: Skip stashing source blocks in verify mode Currently block_image_verify() stashes source blocks to /cache and in some case triggers I/O errors. To avoid this risk, We create a map from the hash value to the source blocks' range_set. When executing stash command in verify mode, source range is saved but block contents aren't stashed. And load_stash could get its value from either the stashed file from the previous update, or the contents on the source partition specified by the saved range. Bug: 27584487 Bug: 25633753 Change-Id: I775baf4bee55762b6e7b204f8294afc597afd996 (cherry picked from commit 0188935d55206e8c2becb29e995f166cb7040355) --- updater/blockimg.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 56378d4f5..9d329cd24 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -67,6 +68,8 @@ struct RangeSet { std::vector pos; // Actual limit is INT_MAX. }; +static std::map stash_map; + static void parse_range(const std::string& range_text, RangeSet& rs) { std::vector pieces = android::base::Split(range_text, ","); @@ -522,8 +525,28 @@ static void DeleteStash(const std::string& base) { } } -static int LoadStash(const std::string& base, const std::string& id, bool verify, size_t* blocks, - std::vector& buffer, bool printnoent) { +static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id, + bool verify, size_t* blocks, std::vector& buffer, bool printnoent) { + // In verify mode, if source range_set was saved for the given hash, + // check contents in the source blocks first. If the check fails, + // search for the stashed files on /cache as usual. + if (!params.canwrite) { + if (stash_map.find(id) != stash_map.end()) { + const RangeSet& src = stash_map[id]; + allocate(src.size * BLOCKSIZE, buffer); + + if (ReadBlocks(src, buffer, params.fd) == -1) { + fprintf(stderr, "failed to read source blocks in stash map.\n"); + return -1; + } + if (VerifyBlocks(id, buffer, src.size, true) != 0) { + fprintf(stderr, "failed to verify loaded source blocks in stash map.\n"); + return -1; + } + return 0; + } + } + if (base.empty()) { return -1; } @@ -722,7 +745,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, const std::string& id = params.tokens[params.cpos++]; size_t blocks = 0; - if (usehash && LoadStash(base, id, true, &blocks, buffer, false) == 0) { + if (usehash && LoadStash(params, base, id, true, &blocks, buffer, false) == 0) { // Stash file already exists and has expected contents. Do not // read from source again, as the source may have been already // overwritten during a previous attempt. @@ -747,6 +770,12 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } + // In verify mode, save source range_set instead of stashing blocks. + if (!params.canwrite && usehash) { + stash_map[id] = src; + return 0; + } + fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str()); return WriteStash(base, id, blocks, buffer, false, nullptr); } @@ -857,7 +886,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } std::vector stash; - int res = LoadStash(stashbase, tokens[0], false, nullptr, stash, true); + int res = LoadStash(params, stashbase, tokens[0], false, nullptr, stash, true); if (res == -1) { // These source blocks will fail verification if used later, but we @@ -931,8 +960,9 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& if (VerifyBlocks(srchash, params.buffer, src_blocks, true) == 0) { // If source and target blocks overlap, stash the source blocks so we can - // resume from possible write errors - if (overlap) { + // resume from possible write errors. In verify mode, we can skip stashing + // because the source blocks won't be overwritten. + if (overlap && params.canwrite) { fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks, srchash.c_str()); @@ -953,7 +983,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& return 0; } - if (overlap && LoadStash(params.stashbase, srchash, true, nullptr, params.buffer, true) == 0) { + if (overlap && LoadStash(params, params.stashbase, srchash, true, nullptr, params.buffer, + true) == 0) { // Overlapping source blocks were previously stashed, command can proceed. // We are recovering from an interrupted command, so we don't know if the // stash can safely be deleted after this command. @@ -1028,8 +1059,15 @@ static int PerformCommandFree(CommandParameters& params) { return -1; } + const std::string& id = params.tokens[params.cpos++]; + + if (!params.canwrite && stash_map.find(id) != stash_map.end()) { + stash_map.erase(id); + return 0; + } + if (params.createdstash || params.canwrite) { - return FreeStash(params.stashbase, params.tokens[params.cpos++]); + return FreeStash(params.stashbase, id); } return 0; -- cgit v1.2.3 From bcabd0929316fdd022ea102cc86396547ad9f070 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 22 Mar 2016 20:19:22 -0700 Subject: Switch to . Change-Id: I13ba3f40bd52b5f3e3fe9002a45a9a8630040129 --- updater/blockimg.cpp | 42 +++++++++++++++++------------------------- 1 file changed, 17 insertions(+), 25 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 9d329cd24..908e11631 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -40,6 +40,7 @@ #include #include +#include #include "applypatch/applypatch.h" #include "edify/expr.h" @@ -48,7 +49,6 @@ #include "minzip/Hash.h" #include "ota_io.h" #include "print_sha1.h" -#include "unique_fd.h" #include "updater.h" #define BLOCKSIZE 4096 @@ -368,7 +368,7 @@ struct CommandParameters { std::string stashbase; bool canwrite; int createdstash; - int fd; + android::base::unique_fd fd; bool foundwrites; bool isunresumable; int version; @@ -577,9 +577,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s return -1; } - int fd = TEMP_FAILURE_RETRY(ota_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; @@ -634,9 +632,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(ota_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; @@ -658,9 +656,8 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } std::string dname = GetStashFileName(base, "", ""); - int dfd = TEMP_FAILURE_RETRY(ota_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) { fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); return -1; @@ -942,8 +939,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; } @@ -1385,9 +1382,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg return StringValue(strdup("")); } - params.fd = TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR)); - unique_fd fd_holder(params.fd); - + params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR))); if (params.fd == -1) { fprintf(stderr, "open \"%s\" failed: %s\n", blockdev_filename->data, strerror(errno)); return StringValue(strdup("")); @@ -1532,7 +1527,7 @@ pbiudone: if (ota_fsync(params.fd) == -1) { 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. @@ -1653,9 +1648,8 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) return StringValue(strdup("")); } - int fd = ota_open(blockdev_filename->data, O_RDWR); - unique_fd fd_holder(fd); - if (fd < 0) { + android::base::unique_fd fd(ota_open(blockdev_filename->data, O_RDWR)); + if (fd == -1) { ErrorAbort(state, "open \"%s\" failed: %s", blockdev_filename->data, strerror(errno)); return StringValue(strdup("")); } @@ -1676,7 +1670,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) for (size_t j = rs.pos[i*2]; j < rs.pos[i*2+1]; ++j) { if (read_all(fd, buffer, BLOCKSIZE) == -1) { ErrorAbort(state, "failed to read %s: %s", blockdev_filename->data, - strerror(errno)); + strerror(errno)); return StringValue(strdup("")); } @@ -1707,8 +1701,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) return StringValue(strdup("")); } - int fd = ota_open(arg_filename->data, O_RDONLY); - unique_fd fd_holder(fd); + android::base::unique_fd fd(ota_open(arg_filename->data, O_RDONLY)); if (fd == -1) { ErrorAbort(state, "open \"%s\" failed: %s", arg_filename->data, strerror(errno)); return StringValue(strdup("")); @@ -1718,8 +1711,7 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) std::vector block0_buffer(BLOCKSIZE); if (ReadBlocks(blk0, block0_buffer, fd) == -1) { - ErrorAbort(state, "failed to read %s: %s", arg_filename->data, - strerror(errno)); + ErrorAbort(state, "failed to read %s: %s", arg_filename->data, strerror(errno)); return StringValue(strdup("")); } -- cgit v1.2.3 From 4bbd5bf8a6383d31341221b97e5e320d5abba085 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 1 Apr 2016 18:24:39 -0700 Subject: Move selinux dependencies out of header files. Bug: http://b/27764900 Change-Id: Ib62a59edcb13054f40f514c404d32b87b14ed5f1 --- updater/install.cpp | 3 ++- updater/updater.cpp | 3 +++ updater/updater.h | 4 +--- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index bc4cca913..925604f31 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -40,6 +39,8 @@ #include #include #include +#include +#include #include "bootloader.h" #include "applypatch/applypatch.h" diff --git a/updater/updater.cpp b/updater/updater.cpp index 1693fa1db..0497d6a85 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -27,6 +27,9 @@ #include "minzip/SysUtil.h" #include "config.h" +#include +#include + // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the // registration functions for device-specific extensions. diff --git a/updater/updater.h b/updater/updater.h index d1dfdd05e..d3a09b93d 100644 --- a/updater/updater.h +++ b/updater/updater.h @@ -20,9 +20,6 @@ #include #include "minzip/Zip.h" -#include -#include - typedef struct { FILE* cmd_pipe; ZipArchive* package_zip; @@ -32,6 +29,7 @@ typedef struct { size_t package_zip_len; } UpdaterInfo; +struct selabel_handle; extern struct selabel_handle *sehandle; #endif -- cgit v1.2.3 From 452df6d99c81c4eeee3d2c7b2171901e8b7bc54a Mon Sep 17 00:00:00 2001 From: Mattias Nissler Date: Mon, 4 Apr 2016 16:17:01 +0200 Subject: Convert recovery to use BoringSSL instead of mincrypt. This changes the verification code in bootable/recovery to use BoringSSL instead of mincrypt. Change-Id: I37b37d84b22e81c32ac180cd1240c02150ddf3a7 --- updater/Android.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 47c56ccd9..7c3f6160c 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -34,6 +34,7 @@ LOCAL_STATIC_LIBRARIES += \ libfec_rs \ libext4_utils_static \ libsquashfs_utils \ + libcrypto_utils_static \ libcrypto_static \ libapplypatch \ libbase \ -- cgit v1.2.3 From 54a2747ef305c10d07d8db393125dbcbb461c428 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Mon, 18 Apr 2016 11:30:55 -0700 Subject: Fix google-runtime-int warnings. Bug: 28220065 Change-Id: Ida199c66692a1638be6990d583d2ed42583fb592 --- updater/install.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 925604f31..4f5268401 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -602,8 +602,8 @@ Value* PackageExtractFileFn(const char* name, State* state, v->size = mzGetZipEntryUncompLen(entry); v->data = reinterpret_cast(malloc(v->size)); if (v->data == NULL) { - printf("%s: failed to allocate %ld bytes for %s\n", - name, (long)v->size, zip_path); + printf("%s: failed to allocate %zd bytes for %s\n", + name, v->size, zip_path); goto done1; } @@ -992,7 +992,8 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { buffer = reinterpret_cast(malloc(st.st_size+1)); if (buffer == NULL) { - ErrorAbort(state, "%s: failed to alloc %lld bytes", name, (long long)st.st_size+1); + ErrorAbort(state, "%s: failed to alloc %zu bytes", name, + static_cast(st.st_size+1)); goto done; } @@ -1004,8 +1005,8 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } if (ota_fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { - ErrorAbort(state, "%s: failed to read %lld bytes from %s", - name, (long long)st.st_size+1, filename); + ErrorAbort(state, "%s: failed to read %zu bytes from %s", + name, static_cast(st.st_size), filename); ota_fclose(f); goto done; } -- cgit v1.2.3 From 730646199b8de879621e97d3196d49f8b71afdda Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 26 Apr 2016 17:14:32 -0700 Subject: updater: Don't zero out CommandParameters with memset(3). [1] switched a few things to android::base::unique_fd including CommandParameters.fd. However, we were using memset(3) to zero out the struct, which effectively assigned unique_fd(0) to fd. When it called fd.reset(), file descriptor 0 was unintentionally closed. When FD 0 was later reassigned via open(2), it led to lseek(2) errors: "Bad file descriptor". This CL switches to using braced-init (i.e. '= {}') instead, so that the default constructor unique_fd(-1) would be called. [1]: commit bcabd0929316fdd022ea102cc86396547ad9f070 Bug: 28391985 Change-Id: If1f99932b15552714c399e65c8b80550344b758a --- updater/blockimg.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 908e11631..2e30c5bf3 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1318,8 +1318,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"); -- cgit v1.2.3 From 49c5c79df15700f9f6e3a349b204edd1548f4357 Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Fri, 29 Apr 2016 14:16:35 -0700 Subject: Fix google-explicit-constructor warnings. Bug: 28341362 Change-Id: I5b35ae16c069e7e9229e66963386f322bd808af1 --- updater/blockimg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 908e11631..2aca9e93d 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -192,7 +192,7 @@ static void allocate(size_t size, std::vector& buffer) { } struct RangeSinkState { - RangeSinkState(RangeSet& rs) : tgt(rs) { }; + explicit RangeSinkState(RangeSet& rs) : tgt(rs) { }; int fd; const RangeSet& tgt; -- cgit v1.2.3 From 733285fea265af4fc91cf37916fada1a66cec470 Mon Sep 17 00:00:00 2001 From: Alistair Strachan Date: Thu, 5 May 2016 16:04:32 -0700 Subject: updater, minzip: Remove unnecessary O_SYNC flags. Remove O_SYNC from mzExtractRecursive() and PackageExtractFileFn(). These functions deal with extracting whole files from the update package onto a filesystem. If run on ext4 on a rotating disk, for example, the O_SYNC flag will cause serious performance problems and the extraction proecss can take over 30 minutes, with no obvious benefits. This API function already calls fsync(fd) after each file is extracted to ensure data and metadata is written to the underlying block device, so the O_SYNC calls should be superfluous and safely removable. This change does not affect the OTA patch paths or any modification of the bootloader partition or writes to other 'emmc' partitions. Signed-off-by: Alistair Strachan Change-Id: I9cbb98a98e6278bf5c0d7efaae340773d1fbfcd2 --- updater/install.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 4f5268401..bab2fe166 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -559,7 +559,7 @@ Value* PackageExtractFileFn(const char* name, State* state, } { - 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)); -- cgit v1.2.3 From 3f6eb86390e27707d1204e60e33b6a41e88f0dc8 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 23 May 2016 14:58:53 -0700 Subject: resolve merge conflicts of 50f6417 Fix a typo for ota_fclose(). Change-Id: Ia93e911aa5391afc604874fc3a09c5a45c094c80 --- updater/install.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index dc2756141..a65b32d81 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1013,7 +1013,6 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } if (ota_fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { - ota_fclose(f); ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", name, static_cast(st.st_size), filename); ota_fclose(f); -- cgit v1.2.3 From 63a319201fc0f5c34c1c62b446527e06f57f8d40 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 9 Jun 2016 17:41:22 -0700 Subject: Remove obsolete MTD support. Bug: http://b/29250988 Change-Id: Ia97ba9082a165c37f74d6e1c3f71a367adc59945 --- updater/Android.mk | 5 +- updater/install.cpp | 168 ++++------------------------------------------------ 2 files changed, 12 insertions(+), 161 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 7c3f6160c..75af4bdd0 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -40,8 +40,8 @@ LOCAL_STATIC_LIBRARIES += \ libbase \ libotafault \ libedify \ - libmtdutils \ libminzip \ + libmounts \ libz \ libbz \ libcutils \ @@ -60,14 +60,11 @@ LOCAL_STATIC_LIBRARIES += \ libtune2fs \ $(tune2fs_static_libraries) -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_C_INCLUDES += external/e2fsprogs/misc LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. diff --git a/updater/install.cpp b/updater/install.cpp index bab2fe166..a6a29b286 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -50,17 +50,14 @@ #include "edify/expr.h" #include "openssl/sha.h" #include "minzip/DirUtil.h" -#include "mtdutils/mounts.h" -#include "mtdutils/mtdutils.h" +#include "mounts.h" #include "ota_io.h" #include "updater.h" #include "install.h" #include "tune2fs.h" -#ifdef USE_EXT4 #include "make_ext4fs.h" #include "wipe.h" -#endif // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { @@ -109,7 +106,6 @@ char* PrintSha1(const uint8_t* digest) { // 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; @@ -170,33 +166,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: @@ -226,7 +203,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 { @@ -256,7 +233,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(""); @@ -292,7 +269,6 @@ 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= mount_point= // fs_type="ext4" partition_type="EMMC" location=device fs_size= mount_point= // fs_type="f2fs" partition_type="EMMC" location=device fs_size= mount_point= // if fs_size == 0, then make fs uses the entire partition. @@ -332,35 +308,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", @@ -387,7 +335,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); @@ -1059,98 +1006,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, "partition argument to %s must be string", name); - goto done; - } - partition = partition_value->data; - if (strlen(partition) == 0) { - ErrorAbort(state, "partition argument to %s can't be empty", name); - goto done; - } - if (contents->type == VAL_STRING && strlen((char*) contents->data) == 0) { - ErrorAbort(state, "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(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[]) { @@ -1607,7 +1462,6 @@ void RegisterInstallFunctions() { RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); - RegisterFunction("write_raw_image", WriteRawImageFn); RegisterFunction("apply_patch", ApplyPatchFn); RegisterFunction("apply_patch_check", ApplyPatchCheckFn); -- cgit v1.2.3 From efacd80364c7ed42d56310949790d89febaf3444 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 11 Jun 2016 03:56:38 -0700 Subject: updater: Fix the broken ReadFileFn. Was accidentally broken by the CL in [1]. [1]: commit d6c93afcc28cc65217ba65eeb646009c4f15a2ad Change-Id: I851e13ccea6f5be6fcd47f712cc95867245f9934 --- updater/install.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index bab2fe166..cfd6a97ee 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1409,7 +1409,7 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { v->data = nullptr; FileContents fc; - if (LoadFileContents(filename, &fc) != 0) { + if (LoadFileContents(filename, &fc) == 0) { v->data = static_cast(malloc(fc.data.size())); if (v->data != nullptr) { memcpy(v->data, fc.data.data(), fc.data.size()); -- cgit v1.2.3 From 83ce7555183a9aa5bac6ccb82d3fa56447d22345 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 30 Jun 2016 09:28:42 -0700 Subject: Fix install.h's use of attribute printf. And move off the bionic __nonnull macro, which I'm removing. Change-Id: I40b4424f4fd7bd8076e0eee3ec35de36c3ded8de --- updater/install.cpp | 3 +-- updater/install.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 11d5215c3..3e7e9285a 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -79,8 +79,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; diff --git a/updater/install.h b/updater/install.h index 70e343404..b3b8a4dd5 100644 --- a/updater/install.h +++ b/updater/install.h @@ -20,8 +20,8 @@ void RegisterInstallFunctions(); // uiPrintf function prints msg to screen as well as logs -void uiPrintf(State* state, const char* format, ...); +void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) __attribute__((__format__(printf, 2, 3))); -static int make_parents(char* name); +static int make_parents(char* _Nonnull name); #endif -- cgit v1.2.3 From 073164f24b212685c181c8620f0397d13e9d79c0 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 5 Aug 2016 15:59:05 -0700 Subject: Fix references to libcrypto_utils_static. Bug: http://b/30708454 Change-Id: I7a5048beff1d8b783a9683dcb4a79606a77f20ee --- updater/Android.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 75af4bdd0..b4d427c5d 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -34,8 +34,8 @@ LOCAL_STATIC_LIBRARIES += \ libfec_rs \ libext4_utils_static \ libsquashfs_utils \ - libcrypto_utils_static \ - libcrypto_static \ + libcrypto_utils \ + libcrypto \ libapplypatch \ libbase \ libotafault \ -- cgit v1.2.3 From 71e182bc3879a53f04a50de9d25c333163cb7c76 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 31 Aug 2016 18:06:33 -0700 Subject: Check an edge case when read(2) returns 0 We might end up in an infinite loop if read(2) reached EOF unexpectedly. The problematic code in uncrypt mentioned in the bug has been fixed by switching to libbase ReadFully(). So I grepped through the recovery code and fixed some other occurences of the issue. Bug: 31073201 Change-Id: Ib867029158ba23363b8f85d61c25058a635c5a6b --- updater/blockimg.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index f00bc4bff..0caa1acbd 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -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; } -- cgit v1.2.3 From 7b0ad9c638176dc364dabb65b363536055a0ea9c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 5 Aug 2016 18:00:04 -0700 Subject: Switch recovery to libbase logging Clean up the recovery image and switch to libbase logging. Bug: 28191554 Change-Id: Icd999c3cc832f0639f204b5c36cea8afe303ad35 Merged-In: Icd999c3cc832f0639f204b5c36cea8afe303ad35 --- updater/Android.mk | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index b4d427c5d..e4d73a45a 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -37,7 +37,6 @@ LOCAL_STATIC_LIBRARIES += \ libcrypto_utils \ libcrypto \ libapplypatch \ - libbase \ libotafault \ libedify \ libminzip \ @@ -46,7 +45,9 @@ LOCAL_STATIC_LIBRARIES += \ libbz \ libcutils \ liblog \ - libselinux + libselinux \ + libbase \ + liblog tune2fs_static_libraries := \ libext2_com_err \ -- cgit v1.2.3 From cb22040c6303144a42a90f424f29a267e43bef74 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 23 Sep 2016 15:30:55 -0700 Subject: Switch to . Bug: http://b/23102347 Test: boot into recovery. Change-Id: Ib2ca560f1312961c21fbaa294bb068de19cb883e Merged-In: Ib2ca560f1312961c21fbaa294bb068de19cb883e --- updater/install.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 4c4886d51..8c33c2bf3 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -46,7 +47,6 @@ #include "applypatch/applypatch.h" #include "cutils/android_reboot.h" #include "cutils/misc.h" -#include "cutils/properties.h" #include "edify/expr.h" #include "error_code.h" #include "minzip/DirUtil.h" @@ -906,11 +906,10 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { char* key = Evaluate(state, argv[0]); if (key == NULL) return NULL; - char value[PROPERTY_VALUE_MAX]; - property_get(key, value, ""); + std::string value = android::base::GetProperty(key, ""); free(key); - return StringValue(strdup(value)); + return StringValue(strdup(value.c_str())); } @@ -1301,9 +1300,8 @@ 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 = ota_fopen(filename, "r+b"); fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); @@ -1311,12 +1309,9 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { 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); -- cgit v1.2.3 From 7aa88748f6ec4e53333d1a15747bc44826ccc410 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 28 Sep 2016 11:42:17 -0700 Subject: Turn on -Werror for recovery Also remove the 0xff comparison when validating the bootloader message fields. As the fields won't be erased to 0xff after we remove the MTD support. Bug: 28202046 Test: The recovery folder compiles for aosp_x86-eng Change-Id: Ibb30ea1b2b28676fb08c7e92a1e5f7b6ef3247ab --- updater/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index e4d73a45a..507088dcd 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -61,7 +61,7 @@ LOCAL_STATIC_LIBRARIES += \ libtune2fs \ $(tune2fs_static_libraries) -LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-unused-parameter -Werror LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_STATIC_LIBRARIES += \ libsparse_static \ -- cgit v1.2.3 From 59dcb9cbea8fb70ab933fd10d35582b08cd13f37 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 3 Oct 2016 18:06:46 -0700 Subject: edify: Move State.script and State.errmsg to std::string. This way we kill a few strdup() and free() calls. Test: 1. recovery_component_test still passes; 2. Applying an update with the new updater works; 3. The error code in a script with abort("E310: xyz") is recorded into last_install correctly. Change-Id: Ibda4da5937346e058a0d7cc81764d6f02920010a --- updater/updater.cpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index c222cee0d..74a4048fb 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -14,21 +14,23 @@ * limitations under the License. */ +#include "updater.h" + #include #include #include #include +#include +#include +#include + +#include "config.h" #include "edify/expr.h" -#include "updater.h" -#include "install.h" #include "blockimg.h" +#include "install.h" #include "minzip/Zip.h" #include "minzip/SysUtil.h" -#include "config.h" - -#include -#include // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the @@ -140,10 +142,7 @@ int main(int argc, char** argv) { 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) { @@ -160,22 +159,21 @@ int main(int argc, char** argv) { } if (result == NULL) { - if (state.errmsg == NULL) { + 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 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"); } @@ -189,7 +187,6 @@ int main(int argc, char** argv) { } } - free(state.errmsg); return 7; } else { fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); -- cgit v1.2.3 From de40ba59c8e5091221752e9d7c6e072c29a7055f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 5 Oct 2016 23:17:01 -0700 Subject: Update the header path for ext4_utils. Test: `mmma bootable/recovery` Change-Id: I70ccddb3ddf46bb012fdc5f632afc46ebdd5473e --- updater/Android.mk | 1 - updater/install.cpp | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 507088dcd..d9fc72c8f 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -62,7 +62,6 @@ LOCAL_STATIC_LIBRARIES += \ $(tune2fs_static_libraries) LOCAL_CFLAGS += -Wno-unused-parameter -Werror -LOCAL_C_INCLUDES += system/extras/ext4_utils LOCAL_STATIC_LIBRARIES += \ libsparse_static \ libz diff --git a/updater/install.cpp b/updater/install.cpp index 8c33c2bf3..24e35cfb8 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include #include @@ -57,9 +59,6 @@ #include "install.h" #include "tune2fs.h" -#include "make_ext4fs.h" -#include "wipe.h" - // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { UpdaterInfo* ui = reinterpret_cast(state->cookie); -- cgit v1.2.3 From 0c7839ac14a00f32d740c23ddf6df65f2757ece5 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Oct 2016 15:48:37 -0700 Subject: Refactor libupdater into a seperate module. So that we can write native tests for updater functions. This CL adds a testcase for getprop() function. Test: mmma bootable/recovery; Run recovery_component_test on device. Change-Id: Iff4c1ff63c5c71aded2f9686fed6b71cc298c228 --- updater/Android.mk | 111 ++++++++++++++++++++++--------------- updater/blockimg.cpp | 4 +- updater/blockimg.h | 22 -------- updater/include/updater/blockimg.h | 22 ++++++++ updater/include/updater/install.h | 28 ++++++++++ updater/include/updater/updater.h | 35 ++++++++++++ updater/install.cpp | 52 ++++++++--------- updater/install.h | 27 --------- updater/updater.cpp | 8 +-- updater/updater.h | 35 ------------ 10 files changed, 184 insertions(+), 160 deletions(-) delete mode 100644 updater/blockimg.h create mode 100644 updater/include/updater/blockimg.h create mode 100644 updater/include/updater/install.h create mode 100644 updater/include/updater/updater.h delete mode 100644 updater/install.h delete mode 100644 updater/updater.h (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index d9fc72c8f..33e97385e 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -14,41 +14,6 @@ LOCAL_PATH := $(call my-dir) -# updater (static executable) -# =============================== -# Build a statically-linked binary to include in OTA packages. -include $(CLEAR_VARS) - -updater_src_files := \ - install.cpp \ - blockimg.cpp \ - updater.cpp - -LOCAL_CLANG := true -LOCAL_SRC_FILES := $(updater_src_files) - -LOCAL_STATIC_LIBRARIES += \ - $(TARGET_RECOVERY_UPDATER_LIBS) \ - $(TARGET_RECOVERY_UPDATER_EXTRA_LIBS) \ - libfec \ - libfec_rs \ - libext4_utils_static \ - libsquashfs_utils \ - libcrypto_utils \ - libcrypto \ - libapplypatch \ - libotafault \ - libedify \ - libminzip \ - libmounts \ - libz \ - libbz \ - libcutils \ - liblog \ - libselinux \ - libbase \ - liblog - tune2fs_static_libraries := \ libext2_com_err \ libext2_blkid \ @@ -57,17 +22,77 @@ tune2fs_static_libraries := \ libext2_e2p \ libext2fs -LOCAL_STATIC_LIBRARIES += \ +updater_common_static_libraries := \ + libapplypatch \ + libedify \ + libminzip \ + 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) -LOCAL_CFLAGS += -Wno-unused-parameter -Werror -LOCAL_STATIC_LIBRARIES += \ - libsparse_static \ - libz +# libupdater (static library) +# =============================== +include $(CLEAR_VARS) + +LOCAL_MODULE := libupdater + +LOCAL_SRC_FILES := \ + install.cpp \ + blockimg.cpp + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/.. \ + $(LOCAL_PATH)/include \ + external/e2fsprogs/misc + +LOCAL_CFLAGS := \ + -Wno-unused-parameter \ + -Werror -LOCAL_C_INCLUDES += external/e2fsprogs/misc -LOCAL_C_INCLUDES += $(LOCAL_PATH)/.. +LOCAL_EXPORT_C_INCLUDE_DIRS := \ + $(LOCAL_PATH)/include + +LOCAL_STATIC_LIBRARIES := \ + $(updater_common_static_libraries) + +include $(BUILD_STATIC_LIBRARY) + +# 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_()". Here we emit a little C function that @@ -108,8 +133,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 0caa1acbd..433d98026 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -45,12 +45,12 @@ #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 "updater.h" +#include "updater/updater.h" #define BLOCKSIZE 4096 diff --git a/updater/blockimg.h b/updater/blockimg.h deleted file mode 100644 index 2f4ad3c04..000000000 --- a/updater/blockimg.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 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 _UPDATER_BLOCKIMG_H_ -#define _UPDATER_BLOCKIMG_H_ - -void RegisterBlockImageFunctions(); - -#endif diff --git a/updater/include/updater/blockimg.h b/updater/include/updater/blockimg.h new file mode 100644 index 000000000..2f4ad3c04 --- /dev/null +++ b/updater/include/updater/blockimg.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2014 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 _UPDATER_BLOCKIMG_H_ +#define _UPDATER_BLOCKIMG_H_ + +void RegisterBlockImageFunctions(); + +#endif diff --git a/updater/include/updater/install.h b/updater/include/updater/install.h new file mode 100644 index 000000000..8d6ca4728 --- /dev/null +++ b/updater/include/updater/install.h @@ -0,0 +1,28 @@ +/* + * 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. + */ + +#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* _Nonnull state, const char* _Nonnull format, ...) + __attribute__((__format__(printf, 2, 3))); + +#endif diff --git a/updater/include/updater/updater.h b/updater/include/updater/updater.h new file mode 100644 index 000000000..d3a09b93d --- /dev/null +++ b/updater/include/updater/updater.h @@ -0,0 +1,35 @@ +/* + * 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. + */ + +#ifndef _UPDATER_UPDATER_H_ +#define _UPDATER_UPDATER_H_ + +#include +#include "minzip/Zip.h" + +typedef struct { + FILE* cmd_pipe; + ZipArchive* 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 24e35cfb8..86cdd5d32 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "updater/install.h" + #include #include #include @@ -40,24 +42,22 @@ #include #include #include +#include #include #include #include #include -#include "bootloader.h" #include "applypatch/applypatch.h" -#include "cutils/android_reboot.h" -#include "cutils/misc.h" +#include "bootloader.h" #include "edify/expr.h" #include "error_code.h" #include "minzip/DirUtil.h" #include "mounts.h" #include "openssl/sha.h" #include "ota_io.h" -#include "updater.h" -#include "install.h" #include "tune2fs.h" +#include "updater/updater.h" // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { @@ -90,6 +90,27 @@ void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) { uiPrint(state, error_msg); } +// 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; +} + // Take a sha-1 digest and return it as a newly-allocated hex string. char* PrintSha1(const uint8_t* digest) { char* buffer = reinterpret_cast(malloc(SHA_DIGEST_LENGTH*2 + 1)); @@ -569,27 +590,6 @@ Value* PackageExtractFileFn(const char* name, State* state, } } -// 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; -} - // symlink target src1 src2 ... // unlinks any previously existing src1, src2, etc before creating symlinks. Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { diff --git a/updater/install.h b/updater/install.h deleted file mode 100644 index b3b8a4dd5..000000000 --- a/updater/install.h +++ /dev/null @@ -1,27 +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. - */ - -#ifndef _UPDATER_INSTALL_H_ -#define _UPDATER_INSTALL_H_ - -void RegisterInstallFunctions(); - -// uiPrintf function prints msg to screen as well as logs -void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) __attribute__((__format__(printf, 2, 3))); - -static int make_parents(char* _Nonnull name); - -#endif diff --git a/updater/updater.cpp b/updater/updater.cpp index 74a4048fb..45e31e097 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "updater.h" +#include "updater/updater.h" #include #include @@ -27,10 +27,10 @@ #include "config.h" #include "edify/expr.h" -#include "blockimg.h" -#include "install.h" -#include "minzip/Zip.h" #include "minzip/SysUtil.h" +#include "minzip/Zip.h" +#include "updater/blockimg.h" +#include "updater/install.h" // Generated by the makefile, this function defines the // RegisterDeviceExtensions() function, which calls all the diff --git a/updater/updater.h b/updater/updater.h deleted file mode 100644 index d3a09b93d..000000000 --- a/updater/updater.h +++ /dev/null @@ -1,35 +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. - */ - -#ifndef _UPDATER_UPDATER_H_ -#define _UPDATER_UPDATER_H_ - -#include -#include "minzip/Zip.h" - -typedef struct { - FILE* cmd_pipe; - ZipArchive* package_zip; - int version; - - uint8_t* package_zip_addr; - size_t package_zip_len; -} UpdaterInfo; - -struct selabel_handle; -extern struct selabel_handle *sehandle; - -#endif -- cgit v1.2.3 From 361342cbd2af4bbf74ac9e91ddfb2a973220a106 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 8 Feb 2016 11:15:50 -0800 Subject: updater: Kill the duplicate PrintSha1() in install.cpp. Also add a testcase for sha1_check(). Test: mmma bootable/recovery; recovery_component_test passes. Change-Id: I4d06d551a771aec84e460148544f68b247a7e721 --- updater/install.cpp | 55 ++++++++++++++++++----------------------------------- 1 file changed, 19 insertions(+), 36 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 86cdd5d32..3546968d7 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -18,24 +18,24 @@ #include #include +#include +#include +#include #include #include #include #include +#include #include #include #include #include -#include -#include -#include -#include -#include #include -#include -#include +#include +#include #include +#include #include #include @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -54,8 +55,8 @@ #include "error_code.h" #include "minzip/DirUtil.h" #include "mounts.h" -#include "openssl/sha.h" #include "ota_io.h" +#include "print_sha1.h" #include "tune2fs.h" #include "updater/updater.h" @@ -111,19 +112,6 @@ static int make_parents(char* name) { return 0; } -// Take a sha-1 digest and return it as a newly-allocated hex string. -char* PrintSha1(const uint8_t* digest) { - char* buffer = reinterpret_cast(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; -} - // mount(fs_type, partition_type, location, mount_point) // // fs_type="ext4" partition_type="EMMC" location=device @@ -1227,29 +1215,24 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { SHA1(reinterpret_cast(args[0]->data), args[0]->size, digest); if (argc == 1) { - return StringValue(PrintSha1(digest)); + return StringValue(strdup(print_sha1(digest).c_str())); } - 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); + printf("%s(): arg %d is not a string; skipping", name, i); } else if (ParseSha1(args[i]->data, 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); } 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(strdup("")); } // Read a local file and return its contents (the Value* returned -- cgit v1.2.3 From 39119ad8ecd00a9c19fb173c78cb4a8d22a4540a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 10 Oct 2016 22:52:18 -0700 Subject: edify: Some clean-ups to libedify. - Remove dead declarations in expr.h: SetError(), GetError(), ClearError(). - Remove the declaration of Build() out of expr.h. - Use std::unordered_map to implement RegisterFunction() and FindFunction(); kill FinishRegistration(). - Add a testcase for calling unknown functions. Test: mmma bootable/recovery; recovery_component_test passes. Change-Id: I9af6825ae677f92b22d716a4a5682f58522af03b --- updater/updater.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index 45e31e097..c752ebbf3 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -111,7 +111,6 @@ int main(int argc, char** argv) { RegisterInstallFunctions(); RegisterBlockImageFunctions(); RegisterDeviceExtensions(); - FinishRegistration(); // Parse the script. -- cgit v1.2.3 From aced5d9e4e438ba478ce54f9217166b8ab7cc24f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 12 Oct 2016 10:55:04 -0700 Subject: Change StringValue to use std::string Changing the field of 'Value' in edify to std::string from char*. Meanwhile cleaning up the users of 'Value' and switching them to cpp style. Test: compontent tests passed. Bug: 31713288 Change-Id: Iec5a7d601b1e4ca40935bf1c70d325dafecec235 --- updater/blockimg.cpp | 154 ++++++++++++++++++++--------------------- updater/install.cpp | 191 ++++++++++++++++++++++----------------------------- updater/updater.cpp | 8 +-- 3 files changed, 158 insertions(+), 195 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 433d98026..5f9b437fe 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1216,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; } @@ -1248,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(params.patch_start + offset), len)); RangeSinkState rss(tgt); rss.fd = params.fd; @@ -1398,64 +1396,62 @@ 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 blockdev_filename_holder(blockdev_filename, - FreeValue); - std::unique_ptr transfer_list_value_holder(transfer_list_value, - FreeValue); - std::unique_ptr new_data_fn_holder(new_data_fn, FreeValue); - std::unique_ptr patch_data_fn_holder(patch_data_fn, FreeValue); + std::unique_ptr blockdev_filename_holder(blockdev_filename); + std::unique_ptr transfer_list_value_holder(transfer_list_value); + std::unique_ptr new_data_fn_holder(new_data_fn); + std::unique_ptr 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(state->cookie); if (ui == nullptr) { - return StringValue(strdup("")); + return StringValue(""); } FILE* cmd_pipe = ui->cmd_pipe; ZipArchive* 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); + const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data.c_str()); if (patch_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, patch_data_fn->data); - return StringValue(strdup("")); + 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); + const ZipEntry* new_entry = mzFindZipEntry(za, new_data_fn->data.c_str()); if (new_entry == nullptr) { - fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data); - return StringValue(strdup("")); + fprintf(stderr, "%s(): no file \"%s\" in package", name, new_data_fn->data.c_str()); + return StringValue(""); } - params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data, O_RDWR))); + 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) { @@ -1471,24 +1467,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 lines = android::base::Split(transfer_list, "\n"); + std::vector 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); @@ -1497,11 +1490,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; @@ -1509,7 +1502,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 @@ -1520,12 +1513,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; @@ -1589,7 +1582,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); @@ -1623,7 +1616,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 @@ -1721,27 +1714,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 ranges_holder(ranges, FreeValue); - std::unique_ptr blockdev_filename_holder(blockdev_filename, - FreeValue); + std::unique_ptr ranges_holder(ranges); + std::unique_ptr 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(""); } - android::base::unique_fd fd(ota_open(blockdev_filename->data, O_RDWR)); + 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, - strerror(errno)); - return StringValue(strdup("")); + ErrorAbort(state, kFileOpenFailure, "open \"%s\" failed: %s", + blockdev_filename->data.c_str(), strerror(errno)); + return StringValue(""); } RangeSet rs; @@ -1753,16 +1745,16 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) std::vector 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); @@ -1771,7 +1763,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 @@ -1785,27 +1777,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 filename(arg_filename, FreeValue); + std::unique_ptr filename(arg_filename); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); - return StringValue(strdup("")); + return StringValue(""); } - android::base::unique_fd fd(ota_open(arg_filename->data, O_RDONLY)); + 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 {0, 1}/*position*/}; std::vector 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 @@ -1823,7 +1815,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"); } @@ -1835,40 +1827,40 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ return NULL; } - std::unique_ptr filename(arg_filename, FreeValue); - std::unique_ptr ranges(arg_ranges, FreeValue); + std::unique_ptr filename(arg_filename); + std::unique_ptr 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; @@ -1885,8 +1877,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 @@ -1901,8 +1893,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/install.cpp b/updater/install.cpp index 3546968d7..d723b3880 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -116,7 +116,7 @@ static int make_parents(char* name) { // // 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); } @@ -197,7 +197,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 +227,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); } @@ -284,7 +284,7 @@ static int exec_cmd(const char* path, char* const argv[]) { // 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); } @@ -358,7 +358,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); } @@ -397,15 +397,10 @@ done: } Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { - char** paths = reinterpret_cast(malloc(argc * sizeof(char*))); + std::vector 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; } } @@ -413,15 +408,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)); } @@ -483,7 +475,7 @@ Value* PackageExtractDirFn(const char* name, State* state, NULL, NULL, sehandle); free(zip_path); free(dest_path); - return StringValue(strdup(success ? "t" : "")); + return StringValue(success ? "t" : ""); } @@ -536,7 +528,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. @@ -544,10 +536,7 @@ Value* PackageExtractFileFn(const char* name, State* state, char* zip_path; if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; - Value* v = reinterpret_cast(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); @@ -556,23 +545,16 @@ Value* PackageExtractFileFn(const char* name, State* state, goto done1; } - v->size = mzGetZipEntryUncompLen(entry); - v->data = reinterpret_cast(malloc(v->size)); - if (v->data == NULL) { - printf("%s: failed to allocate %zd bytes for %s\n", - name, v->size, zip_path); - goto done1; - } - + v->data.resize(mzGetZipEntryUncompLen(entry)); success = mzExtractZipEntryToBuffer(za, entry, - (unsigned char *)v->data); + reinterpret_cast(&v->data[0])); done1: free(zip_path); if (!success) { - free(v->data); - v->data = NULL; - v->size = -1; + v->data.clear(); + } else { + v->type = VAL_BLOB; } return v; } @@ -584,13 +566,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; } @@ -606,12 +588,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]); @@ -620,7 +602,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 { @@ -883,20 +865,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; - + std::string key; + if (!Evaluate(state, argv[0], &key)) { + return nullptr; + } std::string value = android::base::GetProperty(key, ""); - free(key); - return StringValue(strdup(value.c_str())); + return StringValue(value); } @@ -1015,7 +997,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) @@ -1047,17 +1029,16 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } int patchcount = (argc-4) / 2; - std::unique_ptr arg_values(ReadValueVarArgs(state, argc-4, argv+4), - free); + std::unique_ptr arg_values(ReadValueVarArgs(state, argc-4, argv+4)); if (!arg_values) { return nullptr; } - std::vector> patch_shas; - std::vector> patches; + std::vector> patch_shas; + std::vector> 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) { @@ -1071,7 +1052,7 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } } - std::vector patch_sha_str; + std::vector patch_sha_str; std::vector patch_ptrs; for (int i = 0; i < patchcount; ++i) { patch_sha_str.push_back(patch_shas[i]->data); @@ -1080,9 +1061,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, ...]) @@ -1095,21 +1076,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 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 @@ -1129,7 +1106,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[]) { @@ -1137,7 +1114,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[]) { @@ -1180,10 +1157,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) @@ -1199,32 +1173,32 @@ 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 arg_values(ReadValueVarArgs(state, argc, argv), free); + std::unique_ptr arg_values(ReadValueVarArgs(state, argc, argv)); if (arg_values == nullptr) { return nullptr; } - std::vector> args; + std::vector> 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(args[0]->data), args[0]->size, digest); + SHA1(reinterpret_cast(args[0]->data.c_str()), args[0]->data.size(), digest); if (argc == 1) { - return StringValue(strdup(print_sha1(digest).c_str())); + return StringValue(print_sha1(digest)); } 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) { + } 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) { // Found a match. return args[i].release(); @@ -1232,7 +1206,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { } // Didn't match any of the hex strings; return false. - return StringValue(strdup("")); + return StringValue(""); } // Read a local file and return its contents (the Value* returned @@ -1244,21 +1218,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(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(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; @@ -1326,16 +1291,19 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { // package installation. 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); + size_t status = ota_fwrite(stagestr, to_write, 1, f); ota_fclose(f); free(stagestr); + if (status != to_write) { + return StringValue(""); + } return StringValue(filename); } @@ -1352,11 +1320,14 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { char buffer[sizeof(((struct bootloader_message*)0)->stage)]; FILE* f = ota_fopen(filename, "rb"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - ota_fread(buffer, sizeof(buffer), 1, f); + size_t status = ota_fread(buffer, sizeof(buffer), 1, f); ota_fclose(f); - buffer[sizeof(buffer)-1] = '\0'; + 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[]) { @@ -1378,7 +1349,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[]) { @@ -1387,7 +1358,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[]) { @@ -1418,7 +1389,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() { diff --git a/updater/updater.cpp b/updater/updater.cpp index c752ebbf3..47696b80c 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -151,13 +151,14 @@ 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 (!status) { if (state.errmsg.empty()) { printf("script aborted (no error message)\n"); fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); @@ -188,8 +189,7 @@ int main(int argc, char** argv) { 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) { -- cgit v1.2.3 From 8cf5c8f60f51049278b08ae4cbc31df397b651fd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 8 Sep 2016 20:10:11 -0700 Subject: Replace minzip with libziparchive Clean up the duplicated codes that handle the zip files in bootable/recovery; and rename the library of the remaining utility functions to libotautil. Test: Update package installed successfully on angler. Bug: 19472796 Change-Id: Iea8962fcf3004473cb0322b6bb3a9ea3ca7f679e --- updater/Android.mk | 4 ++- updater/blockimg.cpp | 73 ++++++++++++++------------------------- updater/include/updater/updater.h | 4 +-- updater/install.cpp | 38 ++++++++++++-------- updater/updater.cpp | 53 +++++++++++++++++----------- 5 files changed, 87 insertions(+), 85 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 33e97385e..3c1d0d41f 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -25,7 +25,9 @@ tune2fs_static_libraries := \ updater_common_static_libraries := \ libapplypatch \ libedify \ - libminzip \ + libziparchive \ + libotautil \ + libutils \ libmounts \ libotafault \ libext4_utils_static \ diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 5f9b437fe..f08ca5b0c 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -33,21 +33,21 @@ #include #include -#include #include #include +#include #include #include #include #include +#include #include "applypatch/applypatch.h" #include "edify/expr.h" #include "error_code.h" #include "updater/install.h" #include "openssl/sha.h" -#include "minzip/Hash.h" #include "ota_io.h" #include "print_sha1.h" #include "updater/updater.h" @@ -71,7 +71,7 @@ struct RangeSet { static CauseCode failure_type = kNoCause; static bool is_retry = false; -static std::map stash_map; +static std::unordered_map stash_map; static void parse_range(const std::string& range_text, RangeSet& rs) { @@ -300,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; @@ -309,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(cookie); while (size > 0) { @@ -342,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; } @@ -1351,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) @@ -1429,21 +1407,23 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg } FILE* cmd_pipe = ui->cmd_pipe; - ZipArchive* za = ui->package_zip; + ZipArchiveHandle za = ui->package_zip; if (cmd_pipe == nullptr || za == nullptr) { return StringValue(""); } - const ZipEntry* patch_entry = mzFindZipEntry(za, patch_data_fn->data.c_str()); - if (patch_entry == nullptr) { + 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.c_str()); - if (new_entry == nullptr) { + 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(""); } @@ -1526,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 cmdht_holder(cmdht, mzHashTableFree); - + // Build a map of the available commands + std::unordered_map 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; @@ -1549,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(mzHashTableLookup(cmdht, cmdhash, - const_cast(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; diff --git a/updater/include/updater/updater.h b/updater/include/updater/updater.h index d3a09b93d..f4a2fe874 100644 --- a/updater/include/updater/updater.h +++ b/updater/include/updater/updater.h @@ -18,11 +18,11 @@ #define _UPDATER_UPDATER_H_ #include -#include "minzip/Zip.h" +#include typedef struct { FILE* cmd_pipe; - ZipArchive* package_zip; + ZipArchiveHandle package_zip; int version; uint8_t* package_zip_addr; diff --git a/updater/install.cpp b/updater/install.cpp index d723b3880..a41c5db3c 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -48,14 +49,16 @@ #include #include #include +#include #include "applypatch/applypatch.h" #include "bootloader.h" #include "edify/expr.h" #include "error_code.h" -#include "minzip/DirUtil.h" #include "mounts.h" #include "ota_io.h" +#include "otautil/DirUtil.h" +#include "otautil/ZipUtil.h" #include "print_sha1.h" #include "tune2fs.h" #include "updater/updater.h" @@ -465,14 +468,13 @@ 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(success ? "t" : ""); @@ -495,14 +497,15 @@ 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; } @@ -514,7 +517,7 @@ Value* PackageExtractFileFn(const char* name, State* state, 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; @@ -538,16 +541,21 @@ Value* PackageExtractFileFn(const char* name, State* state, 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->data.resize(mzGetZipEntryUncompLen(entry)); - success = mzExtractZipEntryToBuffer(za, entry, - reinterpret_cast(&v->data[0])); + v->data.resize(entry.uncompressed_length); + if (ExtractToMemory(za, &entry, reinterpret_cast(&v->data[0]), + v->data.size()) != 0) { + printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size()); + } else { + success = true; + } done1: free(zip_path); diff --git a/updater/updater.cpp b/updater/updater.cpp index 47696b80c..7327c52e3 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -21,14 +21,17 @@ #include #include +#include + #include #include #include +#include #include "config.h" #include "edify/expr.h" -#include "minzip/SysUtil.h" -#include "minzip/Zip.h" +#include "otautil/DirUtil.h" +#include "otautil/SysUtil.h" #include "updater/blockimg.h" #include "updater/install.h" @@ -82,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(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(&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. @@ -116,9 +126,10 @@ int main(int argc, char** argv) { 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; } @@ -136,7 +147,7 @@ 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; @@ -187,16 +198,18 @@ int main(int argc, char** argv) { } } + 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.c_str()); } if (updater_info.package_zip) { - mzCloseZipArchive(updater_info.package_zip); + CloseArchive(updater_info.package_zip); } sysReleaseMap(&map); - free(script); return 0; } -- cgit v1.2.3 From fada91ccf2b31d69d72899388b1833186d763d1a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 27 Oct 2016 18:16:06 -0700 Subject: applypatch: Switch the parameter of Value** to std::vector. Test: Unit tests and install-recovery.sh pass on angler and dragon. Change-Id: I328e6554edca667cf850f5584ebf1ac211e3d4d1 --- updater/install.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index a41c5db3c..5f3f675b1 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1061,15 +1061,13 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { } std::vector patch_sha_str; - std::vector patch_ptrs; for (int i = 0; i < patchcount; ++i) { patch_sha_str.push_back(patch_shas[i]->data); - patch_ptrs.push_back(patches[i].get()); } int result = applypatch(source_filename, target_filename, target_sha1, target_size, - patch_sha_str, patch_ptrs.data(), NULL); + patch_sha_str, patches, NULL); return StringValue(result == 0 ? "t" : ""); } -- cgit v1.2.3 From 5fe280ac96a2c13f613b7138bb239c3f36d35c9f Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 17 Oct 2016 18:15:20 -0700 Subject: Cleanup ReadArgs & ReadValueArgs usage ReadArgs will switch to using std::string and std::unique_ptr. Also cleanup the callers. Test: mma & component test passed. Change-Id: I4724406ae6c0c134a27bbd1cdd24ad5d343b2a3b --- updater/blockimg.cpp | 54 ++-- updater/install.cpp | 854 +++++++++++++++++++++++---------------------------- 2 files changed, 411 insertions(+), 497 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index f08ca5b0c..c939cf89d 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1368,18 +1368,15 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg fprintf(stderr, "This update is a retry.\n"); } - Value* blockdev_filename = nullptr; - Value* transfer_list_value = nullptr; - Value* new_data_fn = nullptr; - Value* patch_data_fn = nullptr; - if (ReadValueArgs(state, argv, 4, &blockdev_filename, &transfer_list_value, - &new_data_fn, &patch_data_fn) < 0) { - return StringValue(""); + std::vector> args; + if (!ReadValueArgs(state, 4, argv, &args)) { + return nullptr; } - std::unique_ptr blockdev_filename_holder(blockdev_filename); - std::unique_ptr transfer_list_value_holder(transfer_list_value); - std::unique_ptr new_data_fn_holder(new_data_fn); - std::unique_ptr patch_data_fn_holder(patch_data_fn); + + const Value* blockdev_filename = args[0].get(); + const Value* transfer_list_value = args[1].get(); + const Value* new_data_fn = args[2].get(); + const Value* patch_data_fn = args[3].get(); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", @@ -1689,14 +1686,13 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] } Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) { - Value* blockdev_filename; - Value* ranges; - - if (ReadValueArgs(state, argv, 2, &blockdev_filename, &ranges) < 0) { - return StringValue(""); + std::vector> args; + if (!ReadValueArgs(state, 2, argv, &args)) { + return nullptr; } - std::unique_ptr ranges_holder(ranges); - std::unique_ptr blockdev_filename_holder(blockdev_filename); + + const Value* blockdev_filename = args[0].get(); + const Value* ranges = args[1].get(); if (blockdev_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", @@ -1751,14 +1747,14 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) // if executes successfully and an empty string otherwise. Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) { - Value* arg_filename; - - if (ReadValueArgs(state, argv, 1, &arg_filename) < 0) { + std::vector> args; + if (!ReadValueArgs(state, 1, argv, &args)) { return nullptr; } - std::unique_ptr filename(arg_filename); - if (filename->type != VAL_STRING) { + const Value* arg_filename = args[0].get(); + + if (arg_filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); return StringValue(""); } @@ -1799,15 +1795,13 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[]) { - Value* arg_filename; - Value* arg_ranges; - - if (ReadValueArgs(state, argv, 2, &arg_filename, &arg_ranges) < 0) { - return NULL; + std::vector> args; + if (!ReadValueArgs(state, 2, argv, &args)) { + return nullptr; } - std::unique_ptr filename(arg_filename); - std::unique_ptr ranges(arg_ranges); + const Value* filename = args[0].get(); + const Value* ranges = args[1].get(); if (filename->type != VAL_STRING) { ErrorAbort(state, kArgsParsingFailure, "filename argument to %s must be string", name); diff --git a/updater/install.cpp b/updater/install.cpp index 5f3f675b1..efc96c454 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -119,58 +120,50 @@ static int make_parents(char* name) { // // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = nullptr; if (argc != 4 && argc != 5) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc); } - char* fs_type; - char* partition_type; - char* location; - char* mount_point; - char* mount_options; - bool has_mount_options; + + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& fs_type = args[0]; + const std::string& partition_type = args[1]; + const std::string& location = args[2]; + const std::string& mount_point = args[3]; + std::string mount_options; + if (argc == 5) { - has_mount_options = true; - if (ReadArgs(state, argv, 5, &fs_type, &partition_type, - &location, &mount_point, &mount_options) < 0) { - return NULL; - } - } else { - has_mount_options = false; - if (ReadArgs(state, argv, 4, &fs_type, &partition_type, - &location, &mount_point) < 0) { - return NULL; - } + mount_options = args[4]; } - if (strlen(fs_type) == 0) { - ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name); - goto done; + if (fs_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", + name); } - if (strlen(partition_type) == 0) { - ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", - name); - goto done; + if (partition_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", + name); } - if (strlen(location) == 0) { - ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name); - goto done; + if (location.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", + name); } - if (strlen(mount_point) == 0) { - ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", - name); - goto done; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", + name); } { char *secontext = NULL; if (sehandle) { - selabel_lookup(sehandle, &secontext, mount_point, 0755); + selabel_lookup(sehandle, &secontext, mount_point.c_str(), 0755); setfscreatecon(secontext); } - mkdir(mount_point, 0755); + mkdir(mount_point.c_str(), 0755); if (secontext) { freecon(secontext); @@ -178,90 +171,71 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { } } - if (mount(location, mount_point, fs_type, - MS_NOATIME | MS_NODEV | MS_NODIRATIME, - has_mount_options ? mount_options : "") < 0) { + if (mount(location.c_str(), mount_point.c_str(), fs_type.c_str(), + MS_NOATIME | MS_NODEV | MS_NODIRATIME, mount_options.c_str()) < 0) { uiPrintf(state, "%s: failed to mount %s at %s: %s\n", - name, location, mount_point, strerror(errno)); - result = strdup(""); - } else { - result = mount_point; + name, location.c_str(), mount_point.c_str(), strerror(errno)); + return StringValue(""); } -done: - free(fs_type); - free(partition_type); - free(location); - if (result != mount_point) free(mount_point); - if (has_mount_options) free(mount_options); - return StringValue(result); + return StringValue(mount_point); } // is_mounted(mount_point) Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = nullptr; if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } - char* mount_point; - if (ReadArgs(state, argv, 1, &mount_point) < 0) { - return NULL; + + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - if (strlen(mount_point) == 0) { - ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty"); - goto done; + const std::string& mount_point = args[0]; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "mount_point argument to unmount() can't be empty"); } scan_mounted_volumes(); - { - MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); - if (vol == NULL) { - result = strdup(""); - } else { - result = mount_point; - } + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); + if (vol == nullptr) { + return StringValue(""); } -done: - if (result != mount_point) free(mount_point); - return StringValue(result); + return StringValue(mount_point); } Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = nullptr; if (argc != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } - char* mount_point; - if (ReadArgs(state, argv, 1, &mount_point) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - if (strlen(mount_point) == 0) { - ErrorAbort(state, kArgsParsingFailure, "mount_point argument to unmount() can't be empty"); - goto done; + const std::string& mount_point = args[0]; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "mount_point argument to unmount() can't be empty"); } scan_mounted_volumes(); - { - 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(""); - } else { - int ret = unmount_mounted_volume(vol); - if (ret != 0) { - uiPrintf(state, "unmount of %s failed (%d): %s\n", - mount_point, ret, strerror(errno)); - } - result = mount_point; + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); + if (vol == nullptr) { + uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point.c_str()); + return nullptr; + } else { + int ret = unmount_mounted_volume(vol); + if (ret != 0) { + uiPrintf(state, "unmount of %s failed (%d): %s\n", + mount_point.c_str(), ret, strerror(errno)); } } -done: - if (result != mount_point) free(mount_point); - return StringValue(result); + return StringValue(mount_point); } static int exec_cmd(const char* path, char* const argv[]) { @@ -287,116 +261,108 @@ static int exec_cmd(const char* path, char* const argv[]) { // 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 = nullptr; if (argc != 5) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc); } - char* fs_type; - char* partition_type; - char* location; - char* fs_size; - char* mount_point; - if (ReadArgs(state, argv, 5, &fs_type, &partition_type, &location, &fs_size, &mount_point) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& fs_type = args[0]; + const std::string& partition_type = args[1]; + const std::string& location = args[2]; + const std::string& fs_size = args[3]; + const std::string& mount_point = args[4]; - if (strlen(fs_type) == 0) { - ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name); - goto done; + if (fs_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", + name); + } + if (partition_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "partition_type argument to %s() can't be empty", name); } - if (strlen(partition_type) == 0) { - ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", - name); - goto done; + if (location.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", + name); } - if (strlen(location) == 0) { - ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name); - goto done; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "mount_point argument to %s() can't be empty", name); } - if (strlen(mount_point) == 0) { - ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", - name); - goto done; + int64_t size; + if (!android::base::ParseInt(fs_size.c_str(), &size)) { + return ErrorAbort(state, kArgsParsingFailure, + "%s: failed to parse int in %s\n", name, fs_size.c_str()); } - if (strcmp(fs_type, "ext4") == 0) { - int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); + if (fs_type == "ext4") { + int status = make_ext4fs(location.c_str(), size, mount_point.c_str(), sehandle); if (status != 0) { printf("%s: make_ext4fs failed (%d) on %s", - name, status, location); - result = strdup(""); - goto done; + name, status, location.c_str()); + return StringValue(""); } - result = location; - } else if (strcmp(fs_type, "f2fs") == 0) { - char *num_sectors; - if (asprintf(&num_sectors, "%lld", atoll(fs_size) / 512) <= 0) { - printf("format_volume: failed to create %s command for %s\n", fs_type, location); - result = strdup(""); - goto done; + return StringValue(location); + } else if (fs_type == "f2fs") { + if (size < 0) { + printf("fs_size can't be negative for f2fs: %s", fs_size.c_str()); + return StringValue(""); } + std::string num_sectors = std::to_string(size / 512); + const char *f2fs_path = "/sbin/mkfs.f2fs"; - const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", location, num_sectors, NULL}; + const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", location.c_str(), + num_sectors.c_str(), nullptr}; int status = exec_cmd(f2fs_path, (char* const*)f2fs_argv); - free(num_sectors); if (status != 0) { printf("%s: mkfs.f2fs failed (%d) on %s", - name, status, location); - result = strdup(""); - goto done; + name, status, location.c_str()); + return StringValue(""); } - result = location; + return StringValue(location); } else { printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", - name, fs_type, partition_type); + name, fs_type.c_str(), partition_type.c_str()); } -done: - free(fs_type); - free(partition_type); - if (result != location) free(location); - return StringValue(result); + return nullptr; } Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = nullptr; if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* src_name; - char* dst_name; - - if (ReadArgs(state, argv, 2, &src_name, &dst_name) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - if (strlen(src_name) == 0) { - ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name); - goto done; + const std::string& src_name = args[0]; + std::string& dst_name = args[1]; + + if (src_name.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", + name); } - if (strlen(dst_name) == 0) { - ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); - goto done; + if (dst_name.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", + name); } - if (make_parents(dst_name) != 0) { - ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", - dst_name, strerror(errno)); - } else if (access(dst_name, F_OK) == 0 && access(src_name, F_OK) != 0) { + if (make_parents(&dst_name[0]) != 0) { + return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", + dst_name.c_str(), strerror(errno)); + } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { // File was already moved - result = dst_name; - } else if (rename(src_name, dst_name) != 0) { - ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", - src_name, dst_name, strerror(errno)); - } else { - result = dst_name; + return StringValue(dst_name); + } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { + return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", + src_name.c_str(), dst_name.c_str(), strerror(errno)); } -done: - free(src_name); - if (result != dst_name) free(dst_name); - return StringValue(result); + return StringValue(dst_name); } Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -424,20 +390,28 @@ Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* frac_str; - char* sec_str; - if (ReadArgs(state, argv, 2, &frac_str, &sec_str) < 0) { - return NULL; + + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& frac_str = args[0]; + const std::string& sec_str = args[1]; - double frac = strtod(frac_str, NULL); + double frac; + if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { + return ErrorAbort(state, kArgsParsingFailure, + "%s: failed to parse double in %s\n", name, frac_str.c_str()); + } int sec; - android::base::ParseInt(sec_str, &sec); + if (!android::base::ParseInt(sec_str.c_str(), &sec)) { + return ErrorAbort(state, kArgsParsingFailure, + "%s: failed to parse int in %s\n", name, sec_str.c_str()); + } UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); - free(sec_str); return StringValue(frac_str); } @@ -445,12 +419,18 @@ Value* SetProgressFn(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* frac_str; - if (ReadArgs(state, argv, 1, &frac_str) < 0) { - return NULL; + + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& frac_str = args[0]; - double frac = strtod(frac_str, NULL); + double frac; + if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { + return ErrorAbort(state, kArgsParsingFailure, + "%s: failed to parse double in %s\n", name, frac_str.c_str()); + } UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); fprintf(ui->cmd_pipe, "set_progress %f\n", frac); @@ -464,9 +444,13 @@ Value* PackageExtractDirFn(const char* name, State* state, if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* zip_path; - char* dest_path; - if (ReadArgs(state, argv, 2, &zip_path, &dest_path) < 0) return NULL; + + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& zip_path = args[0]; + const std::string& dest_path = args[1]; ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; @@ -475,8 +459,6 @@ Value* PackageExtractDirFn(const char* name, State* state, bool success = ExtractPackageRecursive(za, zip_path, dest_path, ×tamp, sehandle); - free(zip_path); - free(dest_path); return StringValue(success ? "t" : ""); } @@ -499,54 +481,57 @@ Value* PackageExtractFileFn(const char* name, State* state, 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; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, + argc); + } + const std::string& zip_path = args[0]; + const std::string& dest_path = args[1]; - ZipString zip_string_path(zip_path); + ZipString zip_string_path(zip_path.c_str()); ZipEntry entry; if (FindEntry(za, zip_string_path, &entry) != 0) { - printf("%s: no %s in package\n", name, zip_path); - goto done2; + printf("%s: no %s in package\n", name, zip_path.c_str()); + return StringValue(""); } - { - 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 = ExtractEntryToFile(za, &entry, fd); - if (ota_fsync(fd) == -1) { - printf("fsync of \"%s\" failed: %s\n", dest_path, strerror(errno)); - success = false; - } - if (ota_close(fd) == -1) { - printf("close of \"%s\" failed: %s\n", dest_path, strerror(errno)); - success = false; - } + int fd = TEMP_FAILURE_RETRY(ota_open(dest_path.c_str(), 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.c_str(), strerror(errno)); + return StringValue(""); + } + success = ExtractEntryToFile(za, &entry, fd); + if (ota_fsync(fd) == -1) { + printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + success = false; + } + if (ota_close(fd) == -1) { + printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + success = false; } - done2: - free(zip_path); - free(dest_path); return StringValue(success ? "t" : ""); } else { // The one-argument version returns the contents of the file // as the result. - char* zip_path; - if (ReadArgs(state, argv, 1, &zip_path) < 0) return NULL; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, + argc); + } + const std::string& zip_path = args[0]; Value* v = new Value(VAL_INVALID, ""); ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; - ZipString zip_string_path(zip_path); + ZipString zip_string_path(zip_path.c_str()); ZipEntry entry; if (FindEntry(za, zip_string_path, &entry) != 0) { - printf("%s: no %s in package\n", name, zip_path); - goto done1; + printf("%s: no %s in package\n", name, zip_path.c_str()); + return v; } v->data.resize(entry.uncompressed_length); @@ -557,8 +542,6 @@ Value* PackageExtractFileFn(const char* name, State* state, success = true; } - done1: - free(zip_path); if (!success) { v->data.clear(); } else { @@ -579,34 +562,31 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; } - char** srcs = ReadVarArgs(state, argc-1, argv+1); - if (srcs == NULL) { - return NULL; + std::vector srcs; + if (!ReadArgs(state, argc-1, argv+1, &srcs)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } int bad = 0; - int i; - for (i = 0; i < argc-1; ++i) { - if (unlink(srcs[i]) < 0) { + for (int i = 0; i < argc-1; ++i) { + if (unlink(srcs[i].c_str()) < 0) { if (errno != ENOENT) { printf("%s: failed to remove %s: %s\n", - name, srcs[i], strerror(errno)); + name, srcs[i].c_str(), strerror(errno)); ++bad; } } - if (make_parents(srcs[i])) { + if (make_parents(&srcs[i][0])) { printf("%s: failed to symlink %s to %s: making parents failed\n", - name, srcs[i], target.c_str()); + name, srcs[i].c_str(), target.c_str()); ++bad; } - if (symlink(target.c_str(), srcs[i]) < 0) { + if (symlink(target.c_str(), srcs[i].c_str()) < 0) { printf("%s: failed to symlink %s to %s: %s\n", - name, srcs[i], target.c_str(), strerror(errno)); + name, srcs[i].c_str(), target.c_str(), strerror(errno)); ++bad; } - free(srcs[i]); } - free(srcs); if (bad) { return ErrorAbort(state, kSymlinkFailure, "%s: some symlinks failed", name); } @@ -625,12 +605,13 @@ struct perm_parsed_args { bool has_dmode; mode_t dmode; bool has_selabel; - char* selabel; + const char* selabel; bool has_capabilities; uint64_t capabilities; }; -static struct perm_parsed_args ParsePermArgs(State * state, int argc, char** args) { +static struct perm_parsed_args ParsePermArgs(State * state, int argc, + const std::vector& args) { int i; struct perm_parsed_args parsed; int bad = 0; @@ -639,84 +620,84 @@ static struct perm_parsed_args ParsePermArgs(State * state, int argc, char** arg memset(&parsed, 0, sizeof(parsed)); for (i = 1; i < argc; i += 2) { - if (strcmp("uid", args[i]) == 0) { + if (args[i] == "uid") { int64_t uid; - if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNd64, &uid) == 1) { parsed.uid = uid; parsed.has_uid = true; } else { - uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("gid", args[i]) == 0) { + if (args[i] == "gid") { int64_t gid; - if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNd64, &gid) == 1) { parsed.gid = gid; parsed.has_gid = true; } else { - uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("mode", args[i]) == 0) { + if (args[i] == "mode") { int32_t mode; - if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { parsed.mode = mode; parsed.has_mode = true; } else { - uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("dmode", args[i]) == 0) { + if (args[i] == "dmode") { int32_t mode; - if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { parsed.dmode = mode; parsed.has_dmode = true; } else { - uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("fmode", args[i]) == 0) { + if (args[i] == "fmode") { int32_t mode; - if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { parsed.fmode = mode; parsed.has_fmode = true; } else { - uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("capabilities", args[i]) == 0) { + if (args[i] == "capabilities") { int64_t capabilities; - if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) { + if (sscanf(args[i+1].c_str(), "%" SCNi64, &capabilities) == 1) { parsed.capabilities = capabilities; parsed.has_capabilities = true; } else { - uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } - if (strcmp("selabel", args[i]) == 0) { - if (args[i+1][0] != '\0') { - parsed.selabel = args[i+1]; + if (args[i] == "selabel") { + if (!args[i+1].empty()) { + parsed.selabel = args[i+1].c_str(); parsed.has_selabel = true; } else { - uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); + uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); bad++; } continue; } if (max_warnings != 0) { - printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]); + printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); max_warnings--; if (max_warnings == 0) { printf("ParsedPermArgs: suppressing further warnings\n"); @@ -825,48 +806,34 @@ static int do_SetMetadataRecursive(const char* filename, const struct stat *stat } static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { - int bad = 0; - struct stat sb; - Value* result = NULL; - - bool recursive = (strcmp(name, "set_metadata_recursive") == 0); - if ((argc % 2) != 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects an odd number of arguments, got %d", name, argc); } - char** args = ReadVarArgs(state, argc, argv); - if (args == NULL) return NULL; - - if (lstat(args[0], &sb) == -1) { - result = ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", - name, args[0], strerror(errno)); - goto done; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - { - struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); - - if (recursive) { - recursive_parsed_args = parsed; - recursive_state = state; - bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); - memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); - recursive_state = NULL; - } else { - bad += ApplyParsedPerms(state, args[0], &sb, parsed); - } + struct stat sb; + if (lstat(args[0].c_str(), &sb) == -1) { + return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", + name, args[0].c_str(), strerror(errno)); } -done: - for (int i = 0; i < argc; ++i) { - free(args[i]); - } - free(args); + struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); + int bad = 0; + bool recursive = (strcmp(name, "set_metadata_recursive") == 0); - if (result != NULL) { - return result; + if (recursive) { + recursive_parsed_args = parsed; + recursive_state = state; + bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); + memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + recursive_state = NULL; + } else { + bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); } if (bad > 0) { @@ -896,113 +863,80 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { // per line. # comment lines,blank lines, lines without '=' ignored), // and returns the value for 'key' (or "" if it isn't defined). Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { - char* result = NULL; - char* buffer = NULL; - char* filename; - char* key; - if (ReadArgs(state, argv, 2, &filename, &key) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& filename = args[0]; + const std::string& key = args[1]; struct stat st; - if (stat(filename, &st) < 0) { - ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name, filename, - strerror(errno)); - goto done; + if (stat(filename.c_str(), &st) < 0) { + return ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name, + filename.c_str(), strerror(errno)); } #define MAX_FILE_GETPROP_SIZE 65536 if (st.st_size > MAX_FILE_GETPROP_SIZE) { - ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %d)", filename, name, - MAX_FILE_GETPROP_SIZE); - goto done; - } - - buffer = reinterpret_cast(malloc(st.st_size+1)); - if (buffer == NULL) { - ErrorAbort(state, kFileGetPropFailure, "%s: failed to alloc %zu bytes", name, - static_cast(st.st_size+1)); - goto done; + return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %d)", + filename.c_str(), name, MAX_FILE_GETPROP_SIZE); } - FILE* f; - f = ota_fopen(filename, "rb"); - if (f == NULL) { - ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename, - strerror(errno)); - goto done; + std::string buffer(st.st_size, '\0'); + FILE* f = ota_fopen(filename.c_str(), "rb"); + if (f == nullptr) { + return ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, + filename.c_str(), strerror(errno)); } - if (ota_fread(buffer, 1, st.st_size, f) != static_cast(st.st_size)) { + if (ota_fread(&buffer[0], 1, st.st_size, f) != static_cast(st.st_size)) { ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", - name, static_cast(st.st_size), filename); + name, static_cast(st.st_size), filename.c_str()); ota_fclose(f); - goto done; + return nullptr; } - buffer[st.st_size] = '\0'; ota_fclose(f); - char* line; - line = strtok(buffer, "\n"); - do { - // skip whitespace at start of line - while (*line && isspace(*line)) ++line; + std::vector lines = android::base::Split(buffer, "\n"); + for (size_t i = 0; i < lines.size(); i++) { + std::string line = android::base::Trim(lines[i]); // comment or blank line: skip to next line - if (*line == '\0' || *line == '#') continue; - - char* equal = strchr(line, '='); - if (equal == NULL) { + if (line.empty() || line[0] == '#') { + continue; + } + size_t equal_pos = line.find('='); + if (equal_pos == std::string::npos) { continue; } // trim whitespace between key and '=' - char* key_end = equal-1; - while (key_end > line && isspace(*key_end)) --key_end; - key_end[1] = '\0'; + std::string str = android::base::Trim(line.substr(0, equal_pos - 1)); // not the key we're looking for - if (strcmp(key, line) != 0) continue; - - // skip whitespace after the '=' to the start of the value - char* val_start = equal+1; - while(*val_start && isspace(*val_start)) ++val_start; - - // trim trailing whitespace - char* val_end = val_start + strlen(val_start)-1; - while (val_end > val_start && isspace(*val_end)) --val_end; - val_end[1] = '\0'; + if (key != str) continue; - result = strdup(val_start); - break; - - } while ((line = strtok(NULL, "\n"))); - - if (result == NULL) result = strdup(""); + return StringValue(android::base::Trim(line.substr(equal_pos + 1))); + } - done: - free(filename); - free(key); - free(buffer); - return StringValue(result); + return StringValue(""); } // apply_patch_space(bytes) Value* ApplyPatchSpaceFn(const char* name, State* state, int argc, Expr* argv[]) { - char* bytes_str; - if (ReadArgs(state, argv, 1, &bytes_str) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& bytes_str = args[0]; size_t bytes; - if (!android::base::ParseUint(bytes_str, &bytes)) { - ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n", - name, bytes_str); - free(bytes_str); - return nullptr; + if (!android::base::ParseUint(bytes_str.c_str(), &bytes)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n", + name, bytes_str.c_str()); } return StringValue(CacheSizeCheck(bytes) ? "" : "t"); @@ -1013,61 +947,51 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc < 6 || (argc % 2) == 1) { return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 6 args and an " - "even number, got %d", name, argc); + "even number, got %d", name, argc); } - char* source_filename; - char* target_filename; - char* target_sha1; - char* target_size_str; - if (ReadArgs(state, argv, 4, &source_filename, &target_filename, - &target_sha1, &target_size_str) < 0) { - return NULL; + std::vector args; + if (!ReadArgs(state, 4, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& source_filename = args[0]; + const std::string& target_filename = args[1]; + const std::string& target_sha1 = args[2]; + const std::string& target_size_str = args[3]; size_t target_size; - if (!android::base::ParseUint(target_size_str, &target_size)) { - ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count", - name, target_size_str); - free(source_filename); - free(target_filename); - free(target_sha1); - free(target_size_str); - return nullptr; + if (!android::base::ParseUint(target_size_str.c_str(), &target_size)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count", + name, target_size_str.c_str()); } int patchcount = (argc-4) / 2; - std::unique_ptr arg_values(ReadValueVarArgs(state, argc-4, argv+4)); - if (!arg_values) { + std::vector> arg_values; + if (!ReadValueArgs(state, argc-4, argv+4, &arg_values)) { return nullptr; } - std::vector> patch_shas; - std::vector> 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]); - patches.emplace_back(arg_values.get()[i+1]); - } for (int i = 0; i < patchcount; ++i) { - if (patch_shas[i]->type != VAL_STRING) { - ErrorAbort(state, kArgsParsingFailure, "%s(): sha-1 #%d is not string", name, i); - return nullptr; + if (arg_values[i * 2]->type != VAL_STRING) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): sha-1 #%d is not string", name, + i * 2); } - if (patches[i]->type != VAL_BLOB) { - ErrorAbort(state, kArgsParsingFailure, "%s(): patch #%d is not blob", name, i); - return nullptr; + if (arg_values[i * 2 + 1]->type != VAL_BLOB) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): patch #%d is not blob", name, + i * 2 + 1); } } std::vector patch_sha_str; + std::vector> patches; for (int i = 0; i < patchcount; ++i) { - patch_sha_str.push_back(patch_shas[i]->data); + patch_sha_str.push_back(arg_values[i * 2]->data); + patches.push_back(std::move(arg_values[i * 2 + 1])); } - int result = applypatch(source_filename, target_filename, - target_sha1, target_size, - patch_sha_str, patches, NULL); + int result = applypatch(source_filename.c_str(), target_filename.c_str(), + target_sha1.c_str(), target_size, + patch_sha_str, patches, nullptr); return StringValue(result == 0 ? "t" : ""); } @@ -1080,17 +1004,17 @@ Value* ApplyPatchCheckFn(const char* name, State* state, name, argc); } - char* filename; - if (ReadArgs(state, argv, 1, &filename) < 0) { - return nullptr; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } + const std::string& filename = args[0]; std::vector sha1s; - if (!ReadArgs(state, argc-1, argv+1, &sha1s)) { - return nullptr; + if (!ReadArgs(state, argc - 1, argv + 1, &sha1s)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - - int result = applypatch_check(filename, sha1s); + int result = applypatch_check(filename.c_str(), sha1s); return StringValue(result == 0 ? "t" : ""); } @@ -1098,19 +1022,12 @@ Value* ApplyPatchCheckFn(const char* name, State* state, // This is the updater side handler for ui_print() in edify script. Contents // will be sent over to the recovery side for on-screen display. Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { - char** args = ReadVarArgs(state, argc, argv); - if (args == NULL) { - return NULL; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - std::string buffer; - for (int i = 0; i < argc; ++i) { - buffer += args[i]; - free(args[i]); - } - free(args); - - buffer += "\n"; + std::string buffer = android::base::Join(args, "") + "\n"; uiPrint(state, buffer); return StringValue(buffer); } @@ -1127,14 +1044,17 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc < 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); } - char** args = ReadVarArgs(state, argc, argv); - if (args == NULL) { - return NULL; + + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - char** args2 = reinterpret_cast(malloc(sizeof(char*) * (argc+1))); - memcpy(args2, args, sizeof(char*) * argc); - args2[argc] = NULL; + char* args2[argc+1]; + for (int i = 0; i < argc; i++) { + args2[i] = &args[i][0]; + } + args2[argc] = nullptr; printf("about to run program [%s] with %d args\n", args2[0], argc); @@ -1156,13 +1076,6 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { WTERMSIG(status)); } - int i; - for (i = 0; i < argc; ++i) { - free(args[i]); - } - free(args); - free(args2); - return StringValue(android::base::StringPrintf("%d", status)); } @@ -1179,13 +1092,9 @@ 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 arg_values(ReadValueVarArgs(state, argc, argv)); - if (arg_values == nullptr) { - return nullptr; - } std::vector> args; - for (int i = 0; i < argc; ++i) { - args.emplace_back(arg_values.get()[i]); + if (!ReadValueArgs(state, argc, argv, &args)) { + return nullptr; } if (args[0]->type == VAL_INVALID) { @@ -1221,17 +1130,20 @@ Value* ReadFileFn(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* filename; - if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; + + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; Value* v = new Value(VAL_INVALID, ""); FileContents fc; - if (LoadFileContents(filename, &fc) == 0) { + if (LoadFileContents(filename.c_str(), &fc) == 0) { v->type = VAL_BLOB; v->data = std::string(fc.data.begin(), fc.data.end()); } - free(filename); return v; } @@ -1249,27 +1161,27 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* filename; - char* property; - if (ReadArgs(state, argv, 2, &filename, &property) < 0) return NULL; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& property = args[1]; // zero out the 'command' field of the bootloader message. char buffer[80]; memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command)); - FILE* f = ota_fopen(filename, "r+b"); + FILE* f = ota_fopen(filename.c_str(), "r+b"); fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); ota_fclose(f); - free(filename); std::string reboot_cmd = "reboot,"; - if (property != nullptr) reboot_cmd += property; + reboot_cmd += property; android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd); sleep(5); - free(property); - ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); - return NULL; + return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); } // Store a string value somewhere that future invocations of recovery @@ -1287,26 +1199,28 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* filename; - char* stagestr; - if (ReadArgs(state, argv, 2, &filename, &stagestr) < 0) return NULL; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + std::string& stagestr = args[1]; // Store this value in the misc partition, immediately after the // bootloader message that the main recovery uses to save its // arguments in case of the device restarting midway through // package installation. - FILE* f = ota_fopen(filename, "r+b"); + FILE* f = ota_fopen(filename.c_str(), "r+b"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - size_t to_write = strlen(stagestr) + 1; + size_t to_write = stagestr.size(); 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 = stagestr.substr(0, max_size-1); } - size_t status = ota_fwrite(stagestr, to_write, 1, f); + size_t status = ota_fwrite(stagestr.c_str(), to_write, 1, f); ota_fclose(f); - free(stagestr); if (status != to_write) { return StringValue(""); } @@ -1320,11 +1234,14 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); } - char* filename; - if (ReadArgs(state, argv, 1, &filename) < 0) return NULL; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; char buffer[sizeof(((struct bootloader_message*)0)->stage)]; - FILE* f = ota_fopen(filename, "rb"); + FILE* f = ota_fopen(filename.c_str(), "rb"); fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); size_t status = ota_fread(buffer, sizeof(buffer), 1, f); ota_fclose(f); @@ -1341,21 +1258,25 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); } - char* filename; - char* len_str; - if (ReadArgs(state, argv, 2, &filename, &len_str) < 0) return NULL; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& len_str = args[1]; size_t len; - android::base::ParseUint(len_str, &len); - int fd = ota_open(filename, O_WRONLY, 0644); - int success = wipe_block_device(fd, len); - - free(filename); - free(len_str); + if (!android::base::ParseUint(len_str.c_str(), &len)) { + return nullptr; + } + int fd = ota_open(filename.c_str(), O_WRONLY, 0644); + // The wipe_block_device function in ext4_utils returns 0 on success and 1 + // for failure. + int status = wipe_block_device(fd, len); ota_close(fd); - return StringValue(success ? "t" : ""); + return StringValue((status == 0) ? "t" : ""); } Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -1372,28 +1293,27 @@ Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %d", name, argc); } - char** args = ReadVarArgs(state, argc, argv); - if (args == NULL) { + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name); } - char** args2 = reinterpret_cast(malloc(sizeof(char*) * (argc+1))); + char* args2[argc+1]; // Tune2fs expects the program name as its args[0] - args2[0] = strdup(name); - for (int i = 0; i < argc; ++i) { - args2[i + 1] = args[i]; + args2[0] = const_cast(name); + if (args2[0] == nullptr) { + return nullptr; } - int result = tune2fs_main(argc + 1, args2); for (int i = 0; i < argc; ++i) { - free(args[i]); + args2[i + 1] = &args[i][0]; } - free(args); - free(args2[0]); - free(args2); + // tune2fs changes the file system parameters on an ext2 file system; it + // returns 0 on success. + int result = tune2fs_main(argc + 1, args2); + if (result != 0) { - return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", - name, result); + return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result); } return StringValue("t"); } -- cgit v1.2.3 From 51d516e913753a3a1416130b215591e309f0eb2c Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 14:49:01 -0700 Subject: updater: Fix an off-by-1 bug in file_getprop(). Also add a testcase for file_getprop(). Test: recovery_component_test passes. Change-Id: I8eb2f9a5702b43997ac9f4b29665eea087b1c146 --- updater/install.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index efc96c454..19ba36534 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -860,9 +860,13 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { // file_getprop(file, key) // // interprets 'file' as a getprop-style file (key=value pairs, one -// per line. # comment lines,blank lines, lines without '=' ignored), +// per line. # comment lines, blank lines, lines without '=' ignored), // and returns the value for 'key' (or "" if it isn't defined). Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } + std::vector args; if (!ReadArgs(state, 2, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); @@ -876,11 +880,10 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { filename.c_str(), strerror(errno)); } -#define MAX_FILE_GETPROP_SIZE 65536 - + constexpr off_t MAX_FILE_GETPROP_SIZE = 65536; if (st.st_size > MAX_FILE_GETPROP_SIZE) { - return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %d)", - filename.c_str(), name, MAX_FILE_GETPROP_SIZE); + return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %lld)", + filename.c_str(), name, static_cast(MAX_FILE_GETPROP_SIZE)); } std::string buffer(st.st_size, '\0'); @@ -913,7 +916,7 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } // trim whitespace between key and '=' - std::string str = android::base::Trim(line.substr(0, equal_pos - 1)); + std::string str = android::base::Trim(line.substr(0, equal_pos)); // not the key we're looking for if (key != str) continue; -- cgit v1.2.3 From 0831d0b592b2b4abb317a785d0b27e443b8a83db Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:25:04 -0700 Subject: updater: Fix a bug in DeleteFn(). Also add a testcase for delete() function. Test: recovery_component_test passes. Change-Id: I064d1ad4693c3ed339d0a69eabadd08a61a2ea86 --- updater/install.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 19ba36534..25f6a9106 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -66,7 +66,7 @@ // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { - UpdaterInfo* ui = reinterpret_cast(state->cookie); + UpdaterInfo* ui = static_cast(state->cookie); // "line1\nline2\n" will be split into 3 tokens: "line1", "line2" and "". // So skip sending empty strings to UI. @@ -117,6 +117,7 @@ static int make_parents(char* name) { } // mount(fs_type, partition_type, location, mount_point) +// mount(fs_type, partition_type, location, mount_point, mount_options) // // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { @@ -252,7 +253,6 @@ static int exec_cmd(const char* path, char* const argv[]) { return WEXITSTATUS(status); } - // format(fs_type, partition_type, location, fs_size, mount_point) // // fs_type="ext4" partition_type="EMMC" location=device fs_size= mount_point= @@ -301,14 +301,13 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { if (fs_type == "ext4") { int status = make_ext4fs(location.c_str(), size, mount_point.c_str(), sehandle); if (status != 0) { - printf("%s: make_ext4fs failed (%d) on %s", - name, status, location.c_str()); + printf("%s: make_ext4fs failed (%d) on %s", name, status, location.c_str()); return StringValue(""); } return StringValue(location); } else if (fs_type == "f2fs") { if (size < 0) { - printf("fs_size can't be negative for f2fs: %s", fs_size.c_str()); + printf("%s: fs_size can't be negative for f2fs: %s", name, fs_size.c_str()); return StringValue(""); } std::string num_sectors = std::to_string(size / 512); @@ -318,8 +317,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { num_sectors.c_str(), nullptr}; int status = exec_cmd(f2fs_path, (char* const*)f2fs_argv); if (status != 0) { - printf("%s: mkfs.f2fs failed (%d) on %s", - name, status, location.c_str()); + printf("%s: mkfs.f2fs failed (%d) on %s", name, status, location.c_str()); return StringValue(""); } return StringValue(location); @@ -365,8 +363,14 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(dst_name); } +// delete([filename, ...]) +// Deletes all the filenames listed. Returns the number of files successfully deleted. +// +// delete_recursive([dirname, ...]) +// Recursively deletes dirnames and all their contents. Returns the number of directories +// successfully deleted. Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { - std::vector paths; + std::vector paths(argc); for (int i = 0; i < argc; ++i) { if (!Evaluate(state, argv[i], &paths[i])) { return nullptr; @@ -382,7 +386,7 @@ Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { } } - return StringValue(android::base::StringPrintf("%d", success)); + return StringValue(std::to_string(success)); } -- cgit v1.2.3 From a659d79b923cfce21f13519747d2f16048290849 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:25:04 -0700 Subject: updater: Add a testcase for RenameFn(). Test: recovery_component_test passes. Change-Id: Iba5a0fdf6c79e2bed6b30b8fc19a306c1ab29d8a --- updater/install.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 25f6a9106..ed55ea517 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -293,7 +293,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { } int64_t size; - if (!android::base::ParseInt(fs_size.c_str(), &size)) { + if (!android::base::ParseInt(fs_size, &size)) { return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse int in %s\n", name, fs_size.c_str()); } @@ -329,6 +329,9 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; } +// rename(src_name, dst_name) +// Renames src_name to dst_name. It automatically creates the necessary directories for dst_name. +// Example: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk") Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); -- cgit v1.2.3 From d75003d24c6e33befe041dd0cad7be3df199636c Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 4 Nov 2016 11:31:29 -0700 Subject: Make make_parent() to take const argument Switch to use const std::string; and add corresponding tests. Bug: 32649858 Test: Component tests pass Change-Id: I640f3ec81f1481fa91aa310f8d4d96dac9649cb9 --- updater/install.cpp | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index ed55ea517..cba95f5b0 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -95,25 +95,33 @@ void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) { uiPrint(state, error_msg); } +static bool is_dir(const std::string& dirpath) { + struct stat st; + return stat(dirpath.c_str(), &st) == 0 && S_ISDIR(st.st_mode); +} + // 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; +static bool make_parents(const std::string& name) { + size_t prev_end = 0; + while (prev_end < name.size()) { + size_t next_end = name.find('/', prev_end + 1); + if (next_end == std::string::npos) { + break; + } + std::string dir_path = name.substr(0, next_end); + if (!is_dir(dir_path)) { + int result = mkdir(dir_path.c_str(), 0700); + if (result != 0) { + printf("failed to mkdir %s when make parents for %s: %s\n", dir_path.c_str(), + name.c_str(), strerror(errno)); + return false; + } + + printf("created [%s]\n", dir_path.c_str()); } + prev_end = next_end; } - return 0; + return true; } // mount(fs_type, partition_type, location, mount_point) @@ -342,7 +350,7 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& src_name = args[0]; - std::string& dst_name = args[1]; + const std::string& dst_name = args[1]; if (src_name.empty()) { return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", @@ -352,7 +360,7 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); } - if (make_parents(&dst_name[0]) != 0) { + if (!make_parents(dst_name)) { return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", dst_name.c_str(), strerror(errno)); } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { @@ -583,7 +591,7 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { ++bad; } } - if (make_parents(&srcs[i][0])) { + if (!make_parents(srcs[i])) { printf("%s: failed to symlink %s to %s: making parents failed\n", name, srcs[i].c_str(), target.c_str()); ++bad; -- cgit v1.2.3 From 8992902aab88b26b383d95dd7b35c17934b069d5 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 8 Nov 2016 20:51:31 -0800 Subject: updater: Add more testcase for symlink(). Clean up SymlinkFn() a bit. Also clean up the temp files created when running the tests; otherwise non-empty TemporaryDir won't be removed. Test: recovery_component_test passes. Change-Id: Id3844abebd168c40125c4dcec54e6ef680a83c3a --- updater/install.cpp | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index cba95f5b0..59c54dd4c 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -566,8 +566,9 @@ Value* PackageExtractFileFn(const char* name, State* state, } } -// symlink target src1 src2 ... -// unlinks any previously existing src1, src2, etc before creating symlinks. +// symlink(target, [src1, src2, ...]) +// Creates all sources as symlinks to target. It unlinks any previously existing src1, src2, etc +// before creating symlinks. 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); @@ -579,33 +580,29 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { std::vector srcs; if (!ReadArgs(state, argc-1, argv+1, &srcs)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", + name); } - int bad = 0; - for (int i = 0; i < argc-1; ++i) { - if (unlink(srcs[i].c_str()) < 0) { - if (errno != ENOENT) { - printf("%s: failed to remove %s: %s\n", - name, srcs[i].c_str(), strerror(errno)); - ++bad; - } - } - if (!make_parents(srcs[i])) { + size_t bad = 0; + for (const auto& src : srcs) { + if (unlink(src.c_str()) == -1 && errno != ENOENT) { + printf("%s: failed to remove %s: %s\n", name, src.c_str(), strerror(errno)); + ++bad; + } else if (!make_parents(src)) { printf("%s: failed to symlink %s to %s: making parents failed\n", - name, srcs[i].c_str(), target.c_str()); + name, src.c_str(), target.c_str()); ++bad; - } - if (symlink(target.c_str(), srcs[i].c_str()) < 0) { + } else if (symlink(target.c_str(), src.c_str()) == -1) { printf("%s: failed to symlink %s to %s: %s\n", - name, srcs[i].c_str(), target.c_str(), strerror(errno)); + name, src.c_str(), target.c_str(), strerror(errno)); ++bad; } } - if (bad) { - return ErrorAbort(state, kSymlinkFailure, "%s: some symlinks failed", name); + if (bad != 0) { + return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); } - return StringValue(""); + return StringValue("t"); } struct perm_parsed_args { -- cgit v1.2.3 From ef0eb3b01b66fbbc97908667a3dd1e02d710cbb7 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 14 Nov 2016 21:29:52 -0800 Subject: updater: Fix the wrong return value for package_extract_file(). 'bool success = ExtractEntryToFile()' gives opposite result. Fix the issue and add testcases. Change the one-argument version of package_extract_file() to explicitly abort for non-existent zip entry. Note that this is NOT changing the behavior. Prior to this CL, it aborts from Evaluate() function, by giving a general cause code. Now it returns kPackageExtractFileFailure. BUg: 32903624 Test: recovery_component_test works. Change-Id: I7a273e9c0d9aaaf8c472b2c778f7b8d90362c24f --- updater/install.cpp | 145 +++++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 76 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 59c54dd4c..b885f864e 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -477,93 +477,86 @@ Value* PackageExtractDirFn(const char* name, State* state, return StringValue(success ? "t" : ""); } +// package_extract_file(package_file[, dest_file]) +// Extracts a single package_file from the update package and writes it to dest_file, +// overwriting existing files if necessary. Without the dest_file argument, returns the +// contents of the package file as a binary blob. +Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc < 1 || argc > 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d", name, argc); + } + + if (argc == 2) { + // The two-argument version extracts to a file. -// package_extract_file(package_path, destination_path) -// or -// package_extract_file(package_path) -// to return the entire contents of the file as the result of this -// function (the char* returned is actually a FileContents*). -Value* PackageExtractFileFn(const char* name, State* state, - int argc, Expr* argv[]) { - if (argc < 1 || argc > 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d", - name, argc); + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc); } - bool success = false; - - if (argc == 2) { - // The two-argument version extracts to a file. - - ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; - - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, - argc); - } - const std::string& zip_path = args[0]; - const std::string& dest_path = args[1]; + const std::string& zip_path = args[0]; + const std::string& dest_path = args[1]; - ZipString zip_string_path(zip_path.c_str()); - ZipEntry entry; - if (FindEntry(za, zip_string_path, &entry) != 0) { - printf("%s: no %s in package\n", name, zip_path.c_str()); - return StringValue(""); - } + ZipArchiveHandle za = static_cast(state->cookie)->package_zip; + ZipString zip_string_path(zip_path.c_str()); + ZipEntry entry; + if (FindEntry(za, zip_string_path, &entry) != 0) { + printf("%s: no %s in package\n", name, zip_path.c_str()); + return StringValue(""); + } - int fd = TEMP_FAILURE_RETRY(ota_open(dest_path.c_str(), 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.c_str(), strerror(errno)); - return StringValue(""); - } - success = ExtractEntryToFile(za, &entry, fd); - if (ota_fsync(fd) == -1) { - printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); - success = false; - } - if (ota_close(fd) == -1) { - printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); - success = false; - } + int fd = TEMP_FAILURE_RETRY( + ota_open(dest_path.c_str(), 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.c_str(), strerror(errno)); + return StringValue(""); + } - return StringValue(success ? "t" : ""); - } else { - // The one-argument version returns the contents of the file - // as the result. + bool success = true; + int32_t ret = ExtractEntryToFile(za, &entry, fd); + if (ret != 0) { + printf("%s: Failed to extract entry \"%s\" (%u bytes) to \"%s\": %s\n", name, + zip_path.c_str(), entry.uncompressed_length, dest_path.c_str(), ErrorCodeString(ret)); + success = false; + } + if (ota_fsync(fd) == -1) { + printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + success = false; + } + if (ota_close(fd) == -1) { + printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + success = false; + } - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, - argc); - } - const std::string& zip_path = args[0]; + return StringValue(success ? "t" : ""); + } else { + // The one-argument version returns the contents of the file as the result. - Value* v = new Value(VAL_INVALID, ""); + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc); + } + const std::string& zip_path = args[0]; - ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; - ZipString zip_string_path(zip_path.c_str()); - ZipEntry entry; - if (FindEntry(za, zip_string_path, &entry) != 0) { - printf("%s: no %s in package\n", name, zip_path.c_str()); - return v; - } + ZipArchiveHandle za = static_cast(state->cookie)->package_zip; + ZipString zip_string_path(zip_path.c_str()); + ZipEntry entry; + if (FindEntry(za, zip_string_path, &entry) != 0) { + return ErrorAbort(state, kPackageExtractFileFailure, "%s(): no %s in package", name, + zip_path.c_str()); + } - v->data.resize(entry.uncompressed_length); - if (ExtractToMemory(za, &entry, reinterpret_cast(&v->data[0]), - v->data.size()) != 0) { - printf("%s: faled to extract %zu bytes to memory\n", name, v->data.size()); - } else { - success = true; - } + std::string buffer; + buffer.resize(entry.uncompressed_length); - if (!success) { - v->data.clear(); - } else { - v->type = VAL_BLOB; - } - return v; + int32_t ret = ExtractToMemory(za, &entry, reinterpret_cast(&buffer[0]), buffer.size()); + if (ret != 0) { + return ErrorAbort(state, kPackageExtractFileFailure, + "%s: Failed to extract entry \"%s\" (%zu bytes) to memory: %s", name, + zip_path.c_str(), buffer.size(), ErrorCodeString(ret)); } + + return new Value(VAL_BLOB, buffer); + } } // symlink(target, [src1, src2, ...]) -- cgit v1.2.3 From d0f3088aa95e255b39ed4b83da6b08866c2c3e0c Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 3 Nov 2016 23:52:01 -0700 Subject: updater: Add "write_value()" function. write_value(value, filename) writes 'value' to 'filename'. It can be used to tune device settings when applying an OTA package. For example, write_value("960000", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq"). Bug: 32463933 Test: recovery_component_test passes. Test: Apply an OTA package that contains a call to write_value(), and check the result. Change-Id: Ib009ecb8a45a94353f10c59e2383fe1f49796e35 --- updater/install.cpp | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index b885f864e..da68420e8 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -39,11 +39,12 @@ #include #include -#include +#include #include +#include #include -#include #include +#include #include #include #include @@ -861,7 +862,6 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(value); } - // file_getprop(file, key) // // interprets 'file' as a getprop-style file (key=value pairs, one @@ -1155,6 +1155,33 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { return v; } +// write_value(value, filename) +// Writes 'value' to 'filename'. +// Example: write_value("960000", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq") +Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } + + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); + } + + const std::string& filename = args[1]; + if (filename.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): Filename cannot be empty", name); + } + + const std::string& value = args[0]; + if (!android::base::WriteStringToFile(value, filename)) { + printf("%s: Failed to write to \"%s\": %s\n", name, filename.c_str(), strerror(errno)); + return StringValue(""); + } else { + return StringValue("t"); + } +} + // Immediately reboot the device. Recovery is not finished normally, // so if you reboot into recovery it will re-start applying the // current package (because nothing has cleared the copy of the @@ -1363,6 +1390,7 @@ void RegisterInstallFunctions() { RegisterFunction("read_file", ReadFileFn); RegisterFunction("sha1_check", Sha1CheckFn); RegisterFunction("rename", RenameFn); + RegisterFunction("write_value", WriteValueFn); RegisterFunction("wipe_cache", WipeCacheFn); -- cgit v1.2.3 From 1036d36542c452b8df0200d13029d172646a2719 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 17 Nov 2016 22:49:56 -0800 Subject: updater: Add testcase for package_extract_dir(). Test: recovery_component_test passes. Change-Id: I3af4707bc42c7331ca961be8b967a53de82ea25b --- updater/install.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index da68420e8..6c110732a 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -454,28 +454,32 @@ Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(frac_str); } -// package_extract_dir(package_path, destination_path) -Value* PackageExtractDirFn(const char* name, State* state, - int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } +// package_extract_dir(package_dir, dest_dir) +// Extracts all files from the package underneath package_dir and writes them to the +// corresponding tree beneath dest_dir. Any existing files are overwritten. +// Example: package_extract_dir("system", "/system") +// +// Note: package_dir needs to be a relative path; dest_dir needs to be an absolute path. +Value* PackageExtractDirFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& zip_path = args[0]; - const std::string& dest_path = args[1]; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& zip_path = args[0]; + const std::string& dest_path = args[1]; - ZipArchiveHandle za = ((UpdaterInfo*)(state->cookie))->package_zip; + ZipArchiveHandle za = static_cast(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 + // To create a consistent system image, never use the clock for timestamps. + constexpr struct utimbuf timestamp = { 1217592000, 1217592000 }; // 8/1/2008 default - bool success = ExtractPackageRecursive(za, zip_path, dest_path, ×tamp, sehandle); + bool success = ExtractPackageRecursive(za, zip_path, dest_path, ×tamp, sehandle); - return StringValue(success ? "t" : ""); + return StringValue(success ? "t" : ""); } // package_extract_file(package_file[, dest_file]) -- cgit v1.2.3 From bedf5fc11cea9cc6b92f37597fe8624d25b8d371 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 18 Nov 2016 12:01:26 -0800 Subject: updater: Refactor set_stage() and get_stage() functions. Add read_bootloader_message_from() and write_bootloader_message_to() to allow specifying the BCB device (/misc). Also add testcases for set_stage() and get_stage(). Test: recovery_component_test passes. Test: Build a recovery image and apply a two-step OTA package. Change-Id: If5ab06a1aaaea168d2a9e5dd63c07c0a3190e4ae --- updater/Android.mk | 2 + updater/install.cpp | 135 ++++++++++++++++++++++++++-------------------------- 2 files changed, 69 insertions(+), 68 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 3c1d0d41f..5d328a3fa 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -27,12 +27,14 @@ updater_common_static_libraries := \ libedify \ libziparchive \ libotautil \ + libbootloader_message \ libutils \ libmounts \ libotafault \ libext4_utils_static \ libfec \ libfec_rs \ + libfs_mgr \ liblog \ libselinux \ libsparse_static \ diff --git a/updater/install.cpp b/updater/install.cpp index 6c110732a..b9bc19e2c 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -1196,31 +1196,35 @@ Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) { // partition, or "" (empty string) to boot from the regular boot // partition. Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; - const std::string& property = args[1]; - - // zero out the 'command' field of the bootloader message. - char buffer[80]; - memset(buffer, 0, sizeof(((struct bootloader_message*)0)->command)); - FILE* f = ota_fopen(filename.c_str(), "r+b"); - fseek(f, offsetof(struct bootloader_message, command), SEEK_SET); - ota_fwrite(buffer, sizeof(((struct bootloader_message*)0)->command), 1, f); - ota_fclose(f); + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& property = args[1]; + + // Zero out the 'command' field of the bootloader message. Leave the rest intact. + bootloader_message boot; + std::string err; + if (!read_bootloader_message_from(&boot, filename, &err)) { + printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + return StringValue(""); + } + memset(boot.command, 0, sizeof(boot.command)); + if (!write_bootloader_message_to(boot, filename, &err)) { + printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str()); + return StringValue(""); + } - std::string reboot_cmd = "reboot,"; - reboot_cmd += property; - android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd); + const std::string reboot_cmd = "reboot," + property; + android::base::SetProperty(ANDROID_RB_PROPERTY, reboot_cmd); - sleep(5); - return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); + sleep(5); + return ErrorAbort(state, kRebootFailure, "%s() failed to reboot", name); } // Store a string value somewhere that future invocations of recovery @@ -1234,62 +1238,57 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { // second argument is the string to store; it should not exceed 31 // bytes. Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; - std::string& stagestr = args[1]; - - // Store this value in the misc partition, immediately after the - // bootloader message that the main recovery uses to save its - // arguments in case of the device restarting midway through - // package installation. - FILE* f = ota_fopen(filename.c_str(), "r+b"); - fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - size_t to_write = stagestr.size(); - size_t max_size = sizeof(((struct bootloader_message*)0)->stage); - if (to_write > max_size) { - to_write = max_size; - stagestr = stagestr.substr(0, max_size-1); - } - size_t status = ota_fwrite(stagestr.c_str(), to_write, 1, f); - ota_fclose(f); + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& stagestr = args[1]; + + // Store this value in the misc partition, immediately after the + // bootloader message that the main recovery uses to save its + // arguments in case of the device restarting midway through + // package installation. + bootloader_message boot; + std::string err; + if (!read_bootloader_message_from(&boot, filename, &err)) { + printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + return StringValue(""); + } + strlcpy(boot.stage, stagestr.c_str(), sizeof(boot.stage)); + if (!write_bootloader_message_to(boot, filename, &err)) { + printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str()); + return StringValue(""); + } - if (status != to_write) { - return StringValue(""); - } - return StringValue(filename); + return StringValue(filename); } // Return the value most recently saved with SetStageFn. The argument // is the block device for the misc partition. Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); - } + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; - char buffer[sizeof(((struct bootloader_message*)0)->stage)]; - FILE* f = ota_fopen(filename.c_str(), "rb"); - fseek(f, offsetof(struct bootloader_message, stage), SEEK_SET); - size_t status = ota_fread(buffer, sizeof(buffer), 1, f); - ota_fclose(f); - if (status != sizeof(buffer)) { - return StringValue(""); - } + bootloader_message boot; + std::string err; + if (!read_bootloader_message_from(&boot, filename, &err)) { + printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + return StringValue(""); + } - buffer[sizeof(buffer)-1] = '\0'; - return StringValue(buffer); + return StringValue(boot.stage); } Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) { -- cgit v1.2.3 From 358c2ec1dca24d48a503b441d38545ace021ea8e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 28 Nov 2016 11:48:43 -0800 Subject: Remove ota_close(int) and ota_fclose(FILE*). We should always use unique_fd or unique_file to hold the FD or FILE* pointer when opening via ota_(f)open functions. This CL avoids accidentally closing raw FDs or FILE* pointers that are managed by unique_fd/unique_file. Test: recovery_component_test passes. Change-Id: If58eb8b5c5da507563f85efd5d56276472a1c957 --- updater/install.cpp | 142 +++++++++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 73 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index b9bc19e2c..8db5c1fe0 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -509,8 +509,8 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv return StringValue(""); } - int fd = TEMP_FAILURE_RETRY( - ota_open(dest_path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)); + unique_fd fd(TEMP_FAILURE_RETRY( + ota_open(dest_path.c_str(), 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.c_str(), strerror(errno)); return StringValue(""); @@ -872,68 +872,67 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { // per line. # comment lines, blank lines, lines without '=' ignored), // and returns the value for 'key' (or "" if it isn't defined). Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; - const std::string& key = args[1]; + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& key = args[1]; - struct stat st; - if (stat(filename.c_str(), &st) < 0) { - return ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name, - filename.c_str(), strerror(errno)); - } + struct stat st; + if (stat(filename.c_str(), &st) < 0) { + return ErrorAbort(state, kFileGetPropFailure, "%s: failed to stat \"%s\": %s", name, + filename.c_str(), strerror(errno)); + } - constexpr off_t MAX_FILE_GETPROP_SIZE = 65536; - if (st.st_size > MAX_FILE_GETPROP_SIZE) { - return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %lld)", - filename.c_str(), name, static_cast(MAX_FILE_GETPROP_SIZE)); - } + constexpr off_t MAX_FILE_GETPROP_SIZE = 65536; + if (st.st_size > MAX_FILE_GETPROP_SIZE) { + return ErrorAbort(state, kFileGetPropFailure, "%s too large for %s (max %lld)", + filename.c_str(), name, static_cast(MAX_FILE_GETPROP_SIZE)); + } - std::string buffer(st.st_size, '\0'); - FILE* f = ota_fopen(filename.c_str(), "rb"); - if (f == nullptr) { - return ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, - filename.c_str(), strerror(errno)); - } + std::string buffer(st.st_size, '\0'); + unique_file f(ota_fopen(filename.c_str(), "rb")); + if (f == nullptr) { + return ErrorAbort(state, kFileOpenFailure, "%s: failed to open %s: %s", name, filename.c_str(), + strerror(errno)); + } - if (ota_fread(&buffer[0], 1, st.st_size, f) != static_cast(st.st_size)) { - ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", - name, static_cast(st.st_size), filename.c_str()); - ota_fclose(f); - return nullptr; - } + if (ota_fread(&buffer[0], 1, st.st_size, f.get()) != static_cast(st.st_size)) { + ErrorAbort(state, kFreadFailure, "%s: failed to read %zu bytes from %s", name, + static_cast(st.st_size), filename.c_str()); + return nullptr; + } - ota_fclose(f); + ota_fclose(f); - std::vector lines = android::base::Split(buffer, "\n"); - for (size_t i = 0; i < lines.size(); i++) { - std::string line = android::base::Trim(lines[i]); + std::vector lines = android::base::Split(buffer, "\n"); + for (size_t i = 0; i < lines.size(); i++) { + std::string line = android::base::Trim(lines[i]); - // comment or blank line: skip to next line - if (line.empty() || line[0] == '#') { - continue; - } - size_t equal_pos = line.find('='); - if (equal_pos == std::string::npos) { - continue; - } + // comment or blank line: skip to next line + if (line.empty() || line[0] == '#') { + continue; + } + size_t equal_pos = line.find('='); + if (equal_pos == std::string::npos) { + continue; + } - // trim whitespace between key and '=' - std::string str = android::base::Trim(line.substr(0, equal_pos)); + // trim whitespace between key and '=' + std::string str = android::base::Trim(line.substr(0, equal_pos)); - // not the key we're looking for - if (key != str) continue; + // not the key we're looking for + if (key != str) continue; - return StringValue(android::base::Trim(line.substr(equal_pos + 1))); - } + return StringValue(android::base::Trim(line.substr(equal_pos + 1))); + } - return StringValue(""); + return StringValue(""); } // apply_patch_space(bytes) @@ -1292,29 +1291,26 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { } Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } - - std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; - const std::string& len_str = args[1]; - - size_t len; - if (!android::base::ParseUint(len_str.c_str(), &len)) { - return nullptr; - } - int fd = ota_open(filename.c_str(), O_WRONLY, 0644); - // The wipe_block_device function in ext4_utils returns 0 on success and 1 - // for failure. - int status = wipe_block_device(fd, len); + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - ota_close(fd); + std::vector args; + if (!ReadArgs(state, 2, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; + const std::string& len_str = args[1]; - return StringValue((status == 0) ? "t" : ""); + size_t len; + if (!android::base::ParseUint(len_str.c_str(), &len)) { + return nullptr; + } + unique_fd fd(ota_open(filename.c_str(), O_WRONLY, 0644)); + // The wipe_block_device function in ext4_utils returns 0 on success and 1 + // for failure. + int status = wipe_block_device(fd, len); + return StringValue((status == 0) ? "t" : ""); } Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { -- cgit v1.2.3 From 039f2da3e464034404afe27aebd93f84fba119b6 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 22 Nov 2016 16:29:50 -0800 Subject: updater: Switch to libbase logging. Test: Build an updater into a package and apply it on device. Change-Id: I289b5768e9b1e44ef78e0479c64dbaa36fb1a685 --- updater/blockimg.cpp | 194 ++++--- updater/install.cpp | 1484 +++++++++++++++++++++++++------------------------- updater/updater.cpp | 309 +++++------ 3 files changed, 994 insertions(+), 993 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index c939cf89d..7257e2399 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -38,6 +37,7 @@ #include #include +#include #include #include #include @@ -52,7 +52,7 @@ #include "print_sha1.h" #include "updater/updater.h" -#define BLOCKSIZE 4096 +static constexpr size_t BLOCKSIZE = 4096; // Set this to 0 to interpret 'erase' transfers to mean do a // BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret @@ -121,7 +121,7 @@ static void parse_range(const std::string& range_text, RangeSet& rs) { return; err: - fprintf(stderr, "failed to parse range '%s'\n", range_text.c_str()); + LOG(ERROR) << "failed to parse range '" << range_text << "'"; exit(1); } @@ -149,11 +149,11 @@ static int read_all(int fd, uint8_t* data, size_t size) { ssize_t r = TEMP_FAILURE_RETRY(ota_read(fd, data+so_far, size-so_far)); if (r == -1) { failure_type = kFreadFailure; - fprintf(stderr, "read failed: %s\n", strerror(errno)); + PLOG(ERROR) << "read failed"; return -1; } else if (r == 0) { failure_type = kFreadFailure; - fprintf(stderr, "read reached unexpected EOF.\n"); + LOG(ERROR) << "read reached unexpected EOF."; return -1; } so_far += r; @@ -171,7 +171,7 @@ static int write_all(int fd, const uint8_t* data, size_t size) { ssize_t w = TEMP_FAILURE_RETRY(ota_write(fd, data+written, size-written)); if (w == -1) { failure_type = kFwriteFailure; - fprintf(stderr, "write failed: %s\n", strerror(errno)); + PLOG(ERROR) << "write failed"; return -1; } written += w; @@ -193,7 +193,7 @@ static bool discard_blocks(int fd, off64_t offset, uint64_t size) { uint64_t args[2] = {static_cast(offset), size}; int status = ioctl(fd, BLKDISCARD, &args); if (status == -1) { - fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno)); + PLOG(ERROR) << "BLKDISCARD ioctl failed"; return false; } return true; @@ -203,7 +203,7 @@ static bool check_lseek(int fd, off64_t offset, int whence) { off64_t rc = TEMP_FAILURE_RETRY(lseek64(fd, offset, whence)); if (rc == -1) { failure_type = kLseekFailure; - fprintf(stderr, "lseek64 failed: %s\n", strerror(errno)); + PLOG(ERROR) << "lseek64 failed"; return false; } return true; @@ -229,7 +229,7 @@ static ssize_t RangeSinkWrite(const uint8_t* data, ssize_t size, void* token) { RangeSinkState* rss = reinterpret_cast(token); if (rss->p_remain == 0) { - fprintf(stderr, "range sink write overrun"); + LOG(ERROR) << "range sink write overrun"; return 0; } @@ -426,7 +426,7 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& std::vector& buffer, int fd) { if (params.cpos + 1 >= params.tokens.size()) { - fprintf(stderr, "invalid parameters\n"); + LOG(ERROR) << "invalid parameters"; return -1; } @@ -455,8 +455,8 @@ static int VerifyBlocks(const std::string& expected, const std::vector& if (hexdigest != expected) { if (printerror) { - fprintf(stderr, "failed to verify blocks (expected %s, read %s)\n", - expected.c_str(), hexdigest.c_str()); + LOG(ERROR) << "failed to verify blocks (expected " << expected << ", read " + << hexdigest << ")"; } return -1; } @@ -492,7 +492,7 @@ static void EnumerateStash(const std::string& dirname, StashCallback callback, v if (directory == nullptr) { if (errno != ENOENT) { - fprintf(stderr, "opendir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno)); + PLOG(ERROR) << "opendir \"" << dirname << "\" failed"; } return; } @@ -515,7 +515,7 @@ static void UpdateFileSize(const std::string& fn, void* data) { struct stat sb; if (stat(fn.c_str(), &sb) == -1) { - fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); + PLOG(ERROR) << "stat \"" << fn << "\" failed"; return; } @@ -529,10 +529,10 @@ static void UpdateFileSize(const std::string& fn, void* data) { static void DeleteFile(const std::string& fn, void* /* data */) { if (!fn.empty()) { - fprintf(stderr, "deleting %s\n", fn.c_str()); + LOG(INFO) << "deleting " << fn; if (unlink(fn.c_str()) == -1 && errno != ENOENT) { - fprintf(stderr, "unlink \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); + PLOG(ERROR) << "unlink \"" << fn << "\" failed"; } } } @@ -548,14 +548,14 @@ static void DeleteStash(const std::string& base) { return; } - fprintf(stderr, "deleting stash %s\n", base.c_str()); + LOG(INFO) << "deleting stash " << base; std::string dirname = GetStashFileName(base, "", ""); EnumerateStash(dirname, DeleteFile, nullptr); if (rmdir(dirname.c_str()) == -1) { if (errno != ENOENT && errno != ENOTDIR) { - fprintf(stderr, "rmdir \"%s\" failed: %s\n", dirname.c_str(), strerror(errno)); + PLOG(ERROR) << "rmdir \"" << dirname << "\" failed"; } } } @@ -571,11 +571,11 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s allocate(src.size * BLOCKSIZE, buffer); if (ReadBlocks(src, buffer, params.fd) == -1) { - fprintf(stderr, "failed to read source blocks in stash map.\n"); + LOG(ERROR) << "failed to read source blocks in stash map."; return -1; } if (VerifyBlocks(id, buffer, src.size, true) != 0) { - fprintf(stderr, "failed to verify loaded source blocks in stash map.\n"); + LOG(ERROR) << "failed to verify loaded source blocks in stash map."; return -1; } return 0; @@ -599,22 +599,21 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (res == -1) { if (errno != ENOENT || printnoent) { - fprintf(stderr, "stat \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); + PLOG(ERROR) << "stat \"" << fn << "\" failed"; } return -1; } - fprintf(stderr, " loading %s\n", fn.c_str()); + LOG(INFO) << " loading " << fn; if ((sb.st_size % BLOCKSIZE) != 0) { - fprintf(stderr, "%s size %" PRId64 " not multiple of block size %d", - fn.c_str(), static_cast(sb.st_size), BLOCKSIZE); + LOG(ERROR) << fn << " size " << sb.st_size << " not multiple of block size " << BLOCKSIZE; return -1; } 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)); + PLOG(ERROR) << "open \"" << fn << "\" failed"; return -1; } @@ -627,7 +626,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s *blocks = sb.st_size / BLOCKSIZE; if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) { - fprintf(stderr, "unexpected contents in %s\n", fn.c_str()); + LOG(ERROR) << "unexpected contents in " << fn; DeleteFile(fn, nullptr); return -1; } @@ -642,7 +641,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks } if (checkspace && CacheSizeCheck(blocks * BLOCKSIZE) != 0) { - fprintf(stderr, "not enough space to write stash\n"); + LOG(ERROR) << "not enough space to write stash"; return -1; } @@ -657,7 +656,7 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks // The file already exists and since the name is the hash of the contents, // it's safe to assume the contents are identical (accidental hash collisions // are unlikely) - fprintf(stderr, " skipping %d existing blocks in %s\n", blocks, cn.c_str()); + LOG(INFO) << " skipping " << blocks << " existing blocks in " << cn; *exists = true; return 0; } @@ -665,13 +664,12 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks *exists = false; } - fprintf(stderr, " writing %d blocks to %s\n", blocks, cn.c_str()); + LOG(INFO) << " writing " << blocks << " blocks to " << cn; - android::base::unique_fd fd(TEMP_FAILURE_RETRY(ota_open(fn.c_str(), - O_WRONLY | O_CREAT | O_TRUNC, - STASH_FILE_MODE))); + 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)); + PLOG(ERROR) << "failed to create \"" << fn << "\""; return -1; } @@ -681,13 +679,12 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks if (ota_fsync(fd) == -1) { failure_type = kFsyncFailure; - fprintf(stderr, "fsync \"%s\" failed: %s\n", fn.c_str(), strerror(errno)); + PLOG(ERROR) << "fsync \"" << fn << "\" failed"; return -1; } if (rename(fn.c_str(), cn.c_str()) == -1) { - fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", fn.c_str(), cn.c_str(), - strerror(errno)); + PLOG(ERROR) << "rename(\"" << fn << "\", \"" << cn << "\") failed"; return -1; } @@ -696,13 +693,13 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks O_RDONLY | O_DIRECTORY))); if (dfd == -1) { failure_type = kFileOpenFailure; - fprintf(stderr, "failed to open \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); + PLOG(ERROR) << "failed to open \"" << dname << "\" failed"; return -1; } if (ota_fsync(dfd) == -1) { failure_type = kFsyncFailure; - fprintf(stderr, "fsync \"%s\" failed: %s\n", dname.c_str(), strerror(errno)); + PLOG(ERROR) << "fsync \"" << dname << "\" failed"; return -1; } @@ -734,7 +731,7 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s dirname.c_str(), strerror(errno)); return -1; } else if (res != 0) { - fprintf(stderr, "creating stash %s\n", dirname.c_str()); + LOG(INFO) << "creating stash " << dirname; res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE); if (res != 0) { @@ -751,7 +748,7 @@ static int CreateStash(State* state, int maxblocks, const char* blockdev, std::s return 1; // Created directory } - fprintf(stderr, "using existing stash %s\n", dirname.c_str()); + LOG(INFO) << "using existing stash " << dirname; // If the directory already exists, calculate the space already allocated to // stash files and check if there's enough for all required blocks. Delete any @@ -777,7 +774,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, // if (params.cpos + 1 >= params.tokens.size()) { - fprintf(stderr, "missing id and/or src range fields in stash command\n"); + LOG(ERROR) << "missing id and/or src range fields in stash command"; return -1; } const std::string& id = params.tokens[params.cpos++]; @@ -804,7 +801,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, // data later, this is an unrecoverable error. However, the command // that uses the data may have already completed previously, so the // possible failure will occur during source block verification. - fprintf(stderr, "failed to load source blocks for stash %s\n", id.c_str()); + LOG(ERROR) << "failed to load source blocks for stash " << id; return 0; } @@ -814,7 +811,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } - fprintf(stderr, "stashing %zu blocks to %s\n", blocks, id.c_str()); + LOG(INFO) << "stashing " << blocks << " blocks to " << id; params.stashed += blocks; return WriteStash(base, id, blocks, buffer, false, nullptr); } @@ -870,7 +867,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& // At least it needs to provide three parameters: , // and "-"/. if (params.cpos + 2 >= params.tokens.size()) { - fprintf(stderr, "invalid parameters\n"); + LOG(ERROR) << "invalid parameters"; return -1; } @@ -880,7 +877,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& // const std::string& token = params.tokens[params.cpos++]; if (!android::base::ParseUint(token.c_str(), &src_blocks)) { - fprintf(stderr, "invalid src_block_count \"%s\"\n", token.c_str()); + LOG(ERROR) << "invalid src_block_count \"" << token << "\""; return -1; } @@ -920,7 +917,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& // stashed data should go. std::vector tokens = android::base::Split(params.tokens[params.cpos++], ":"); if (tokens.size() != 2) { - fprintf(stderr, "invalid parameter\n"); + LOG(ERROR) << "invalid parameter"; return -1; } @@ -930,7 +927,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& if (res == -1) { // These source blocks will fail verification if used later, but we // will let the caller decide if this is a fatal failure - fprintf(stderr, "failed to load stash %s\n", tokens[0].c_str()); + LOG(ERROR) << "failed to load stash " << tokens[0]; continue; } @@ -964,7 +961,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& bool onehash, bool& overlap) { if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing source hash\n"); + LOG(ERROR) << "missing source hash"; return -1; } @@ -975,7 +972,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& tgthash = srchash; } else { if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing target hash\n"); + LOG(ERROR) << "missing target hash"; return -1; } tgthash = params.tokens[params.cpos++]; @@ -1002,13 +999,12 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& // resume from possible write errors. In verify mode, we can skip stashing // because the source blocks won't be overwritten. if (overlap && params.canwrite) { - fprintf(stderr, "stashing %zu overlapping blocks to %s\n", src_blocks, - srchash.c_str()); + LOG(INFO) << "stashing " << src_blocks << " overlapping blocks to " << srchash; bool stash_exists = false; if (WriteStash(params.stashbase, srchash, src_blocks, params.buffer, true, &stash_exists) != 0) { - fprintf(stderr, "failed to stash overlapping source blocks\n"); + LOG(ERROR) << "failed to stash overlapping source blocks"; return -1; } @@ -1032,7 +1028,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& } // Valid source data not available, update cannot be resumed - fprintf(stderr, "partition has unexpected contents\n"); + LOG(ERROR) << "partition has unexpected contents"; params.isunresumable = true; return -1; @@ -1054,25 +1050,25 @@ static int PerformCommandMove(CommandParameters& params) { } if (status == -1) { - fprintf(stderr, "failed to read blocks for move\n"); + LOG(ERROR) << "failed to read blocks for move"; return -1; } if (status == 0) { params.foundwrites = true; } else if (params.foundwrites) { - fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname); + LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; } if (params.canwrite) { if (status == 0) { - fprintf(stderr, " moving %zu blocks\n", blocks); + LOG(INFO) << " moving " << blocks << " blocks"; if (WriteBlocks(tgt, params.buffer, params.fd) == -1) { return -1; } } else { - fprintf(stderr, "skipping %zu already moved blocks\n", blocks); + LOG(INFO) << "skipping " << blocks << " already moved blocks"; } } @@ -1095,7 +1091,7 @@ static int PerformCommandStash(CommandParameters& params) { static int PerformCommandFree(CommandParameters& params) { // if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing stash id in free command\n"); + LOG(ERROR) << "missing stash id in free command"; return -1; } @@ -1116,14 +1112,14 @@ static int PerformCommandFree(CommandParameters& params) { static int PerformCommandZero(CommandParameters& params) { if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing target blocks for zero\n"); + LOG(ERROR) << "missing target blocks for zero"; return -1; } RangeSet tgt; parse_range(params.tokens[params.cpos++], tgt); - fprintf(stderr, " zeroing %zu blocks\n", tgt.size); + LOG(INFO) << " zeroing " << tgt.size << " blocks"; allocate(BLOCKSIZE, params.buffer); memset(params.buffer.data(), 0, BLOCKSIZE); @@ -1160,7 +1156,7 @@ static int PerformCommandZero(CommandParameters& params) { static int PerformCommandNew(CommandParameters& params) { if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing target blocks for new\n"); + LOG(ERROR) << "missing target blocks for new"; return -1; } @@ -1168,7 +1164,7 @@ static int PerformCommandNew(CommandParameters& params) { parse_range(params.tokens[params.cpos++], tgt); if (params.canwrite) { - fprintf(stderr, " writing %zu blocks of new data\n", tgt.size); + LOG(INFO) << " writing " << tgt.size << " blocks of new data"; RangeSinkState rss(tgt); rss.fd = params.fd; @@ -1204,19 +1200,19 @@ static int PerformCommandDiff(CommandParameters& params) { // if (params.cpos + 1 >= params.tokens.size()) { - fprintf(stderr, "missing patch offset or length for %s\n", params.cmdname); + LOG(ERROR) << "missing patch offset or length for " << params.cmdname; return -1; } size_t offset; if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &offset)) { - fprintf(stderr, "invalid patch offset\n"); + LOG(ERROR) << "invalid patch offset"; return -1; } size_t len; if (!android::base::ParseUint(params.tokens[params.cpos++].c_str(), &len)) { - fprintf(stderr, "invalid patch len\n"); + LOG(ERROR) << "invalid patch len"; return -1; } @@ -1234,19 +1230,19 @@ static int PerformCommandDiff(CommandParameters& params) { } if (status == -1) { - fprintf(stderr, "failed to read blocks for diff\n"); + LOG(ERROR) << "failed to read blocks for diff"; return -1; } if (status == 0) { params.foundwrites = true; } else if (params.foundwrites) { - fprintf(stderr, "warning: commands executed out of order [%s]\n", params.cmdname); + LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; } if (params.canwrite) { if (status == 0) { - fprintf(stderr, "patching %zu blocks to %zu\n", blocks, tgt.size); + LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size; Value patch_value(VAL_BLOB, std::string(reinterpret_cast(params.patch_start + offset), len)); @@ -1268,24 +1264,24 @@ static int PerformCommandDiff(CommandParameters& params) { if (params.cmdname[0] == 'i') { // imgdiff if (ApplyImagePatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, &RangeSinkWrite, &rss, nullptr, nullptr) != 0) { - fprintf(stderr, "Failed to apply image patch.\n"); + LOG(ERROR) << "Failed to apply image patch."; return -1; } } else { if (ApplyBSDiffPatch(params.buffer.data(), blocks * BLOCKSIZE, &patch_value, 0, &RangeSinkWrite, &rss, nullptr) != 0) { - fprintf(stderr, "Failed to apply bsdiff patch.\n"); + LOG(ERROR) << "Failed to apply bsdiff patch."; return -1; } } // We expect the output of the patcher to fill the tgt ranges exactly. if (rss.p_block != tgt.count || rss.p_remain != 0) { - fprintf(stderr, "range sink underrun?\n"); + LOG(ERROR) << "range sink underrun?"; } } else { - fprintf(stderr, "skipping %zu blocks already patched to %zu [%s]\n", - blocks, tgt.size, params.cmdline); + LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.size + << " [" << params.cmdline << "]"; } } @@ -1306,17 +1302,17 @@ static int PerformCommandErase(CommandParameters& params) { struct stat sb; if (fstat(params.fd, &sb) == -1) { - fprintf(stderr, "failed to fstat device to erase: %s\n", strerror(errno)); + PLOG(ERROR) << "failed to fstat device to erase"; return -1; } if (!S_ISBLK(sb.st_mode)) { - fprintf(stderr, "not a block device; skipping erase\n"); + LOG(ERROR) << "not a block device; skipping erase"; return -1; } if (params.cpos >= params.tokens.size()) { - fprintf(stderr, "missing target blocks for erase\n"); + LOG(ERROR) << "missing target blocks for erase"; return -1; } @@ -1324,7 +1320,7 @@ static int PerformCommandErase(CommandParameters& params) { parse_range(params.tokens[params.cpos++], tgt); if (params.canwrite) { - fprintf(stderr, " erasing %zu blocks\n", tgt.size); + LOG(INFO) << " erasing " << tgt.size << " blocks"; for (size_t i = 0; i < tgt.count; ++i) { uint64_t blocks[2]; @@ -1334,7 +1330,7 @@ static int PerformCommandErase(CommandParameters& params) { blocks[1] = (tgt.pos[i * 2 + 1] - tgt.pos[i * 2]) * (uint64_t) BLOCKSIZE; if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) { - fprintf(stderr, "BLKDISCARD ioctl failed: %s\n", strerror(errno)); + PLOG(ERROR) << "BLKDISCARD ioctl failed"; return -1; } } @@ -1362,10 +1358,10 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg CommandParameters params = {}; params.canwrite = !dryrun; - fprintf(stderr, "performing %s\n", dryrun ? "verification" : "update"); + LOG(INFO) << "performing " << dryrun ? "verification" : "update"; if (state->is_retry) { is_retry = true; - fprintf(stderr, "This update is a retry.\n"); + LOG(INFO) << "This update is a retry."; } std::vector> args; @@ -1413,7 +1409,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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()); + LOG(ERROR) << name << "(): no file \"" << patch_data_fn->data << "\" in package"; return StringValue(""); } @@ -1421,13 +1417,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg 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()); + LOG(ERROR) << name << "(): no file \"" << new_data_fn->data << "\" in package"; return StringValue(""); } 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.c_str(), strerror(errno)); + PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed"; return StringValue(""); } @@ -1443,7 +1439,7 @@ 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)); + PLOG(ERROR) << "pthread_create failed"; return StringValue(""); } } @@ -1457,11 +1453,11 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg // 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()); + LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]"; return StringValue(""); } - fprintf(stderr, "blockimg version is %d\n", params.version); + LOG(INFO) << "blockimg version is " << params.version; // Second line in transfer list is the total number of blocks we expect to write int total_blocks; @@ -1483,7 +1479,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg } // Third line is how many stash entries are needed simultaneously - fprintf(stderr, "maximum stash entries %s\n", lines[2].c_str()); + LOG(INFO) << "maximum stash entries " << lines[2]; // Fourth line is the maximum number of blocks that will be stashed simultaneously int stash_max_blocks; @@ -1507,8 +1503,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg std::unordered_map cmd_map; for (size_t i = 0; i < cmdcount; ++i) { 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); + LOG(ERROR) << "Error: command [" << commands[i].name + << "] already exists in the cmd map."; return StringValue(strdup("")); } cmd_map[commands[i].name] = &commands[i]; @@ -1529,21 +1525,21 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg params.cmdline = line_str.c_str(); if (cmd_map.find(params.cmdname) == cmd_map.end()) { - fprintf(stderr, "unexpected command [%s]\n", params.cmdname); + LOG(ERROR) << "unexpected command [" << 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()); + LOG(ERROR) << "failed to execute command [" << line_str << "]"; goto pbiudone; } if (params.canwrite) { if (ota_fsync(params.fd) == -1) { failure_type = kFsyncFailure; - fprintf(stderr, "fsync failed: %s\n", strerror(errno)); + PLOG(ERROR) << "fsync failed"; goto pbiudone; } fprintf(cmd_pipe, "set_progress %.4f\n", (double) params.written / total_blocks); @@ -1554,9 +1550,9 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg if (params.canwrite) { pthread_join(params.thread, nullptr); - fprintf(stderr, "wrote %zu blocks; expected %d\n", params.written, total_blocks); - fprintf(stderr, "stashed %zu blocks\n", params.stashed); - fprintf(stderr, "max alloc needed was %zu\n", params.buffer.size()); + LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks; + LOG(INFO) << "stashed " << params.stashed << " blocks"; + LOG(INFO) << "max alloc needed was " << params.buffer.size(); const char* partition = strrchr(blockdev_filename->data.c_str(), '/'); if (partition != nullptr && *(partition+1) != 0) { @@ -1570,7 +1566,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg // may contain blocks needed to complete the update later. DeleteStash(params.stashbase); } else { - fprintf(stderr, "verified partition contents; update may be resumed\n"); + LOG(INFO) << "verified partition contents; update may be resumed"; } rc = 0; @@ -1578,7 +1574,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg pbiudone: if (ota_fsync(params.fd) == -1) { failure_type = kFsyncFailure; - fprintf(stderr, "fsync failed: %s\n", strerror(errno)); + PLOG(ERROR) << "fsync failed"; } // params.fd will be automatically closed because it's a unique_fd. @@ -1813,7 +1809,7 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ } // Output notice to log when recover is attempted - fprintf(stderr, "%s image corrupted, attempting to recover...\n", filename->data.c_str()); + LOG(INFO) << filename->data << " image corrupted, attempting to recover..."; // When opened with O_RDWR, libfec rewrites corrupted blocks when they are read fec::io fh(filename->data.c_str(), O_RDWR); @@ -1866,7 +1862,7 @@ 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.c_str()); + LOG(INFO) << "..." << filename->data << " image recovered successfully."; return StringValue("t"); } diff --git a/updater/install.cpp b/updater/install.cpp index 8db5c1fe0..3cf38774e 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -67,33 +68,33 @@ // Send over the buffer to recovery though the command pipe. static void uiPrint(State* state, const std::string& buffer) { - UpdaterInfo* ui = static_cast(state->cookie); - - // "line1\nline2\n" will be split into 3 tokens: "line1", "line2" and "". - // So skip sending empty strings to UI. - std::vector lines = android::base::Split(buffer, "\n"); - for (auto& line: lines) { - if (!line.empty()) { - fprintf(ui->cmd_pipe, "ui_print %s\n", line.c_str()); - fprintf(ui->cmd_pipe, "ui_print\n"); - } + UpdaterInfo* ui = static_cast(state->cookie); + + // "line1\nline2\n" will be split into 3 tokens: "line1", "line2" and "". + // So skip sending empty strings to UI. + std::vector lines = android::base::Split(buffer, "\n"); + for (auto& line : lines) { + if (!line.empty()) { + fprintf(ui->cmd_pipe, "ui_print %s\n", line.c_str()); + fprintf(ui->cmd_pipe, "ui_print\n"); } + } - // On the updater side, we need to dump the contents to stderr (which has - // been redirected to the log file). Because the recovery will only print - // the contents to screen when processing pipe command ui_print. - fprintf(stderr, "%s", buffer.c_str()); + // On the updater side, we need to dump the contents to stderr (which has + // been redirected to the log file). Because the recovery will only print + // the contents to screen when processing pipe command ui_print. + LOG(INFO) << buffer; } void uiPrintf(State* _Nonnull state, const char* _Nonnull format, ...) { - std::string error_msg; + std::string error_msg; - va_list ap; - va_start(ap, format); - android::base::StringAppendV(&error_msg, format, ap); - va_end(ap); + va_list ap; + va_start(ap, format); + android::base::StringAppendV(&error_msg, format, ap); + va_end(ap); - uiPrint(state, error_msg); + uiPrint(state, error_msg); } static bool is_dir(const std::string& dirpath) { @@ -103,26 +104,25 @@ static bool is_dir(const std::string& dirpath) { // Create all parent directories of name, if necessary. static bool make_parents(const std::string& name) { - size_t prev_end = 0; - while (prev_end < name.size()) { - size_t next_end = name.find('/', prev_end + 1); - if (next_end == std::string::npos) { - break; - } - std::string dir_path = name.substr(0, next_end); - if (!is_dir(dir_path)) { - int result = mkdir(dir_path.c_str(), 0700); - if (result != 0) { - printf("failed to mkdir %s when make parents for %s: %s\n", dir_path.c_str(), - name.c_str(), strerror(errno)); - return false; - } - - printf("created [%s]\n", dir_path.c_str()); - } - prev_end = next_end; - } - return true; + size_t prev_end = 0; + while (prev_end < name.size()) { + size_t next_end = name.find('/', prev_end + 1); + if (next_end == std::string::npos) { + break; + } + std::string dir_path = name.substr(0, next_end); + if (!is_dir(dir_path)) { + int result = mkdir(dir_path.c_str(), 0700); + if (result != 0) { + PLOG(ERROR) << "failed to mkdir " << dir_path << " when make parents for " << name; + return false; + } + + LOG(INFO) << "created [" << dir_path << "]"; + } + prev_end = next_end; + } + return true; } // mount(fs_type, partition_type, location, mount_point) @@ -130,249 +130,242 @@ static bool make_parents(const std::string& name) { // // fs_type="ext4" partition_type="EMMC" location=device Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 4 && argc != 5) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc); - } + if (argc != 4 && argc != 5) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& fs_type = args[0]; - const std::string& partition_type = args[1]; - const std::string& location = args[2]; - const std::string& mount_point = args[3]; - std::string mount_options; - - if (argc == 5) { - mount_options = args[4]; - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& fs_type = args[0]; + const std::string& partition_type = args[1]; + const std::string& location = args[2]; + const std::string& mount_point = args[3]; + std::string mount_options; + + if (argc == 5) { + mount_options = args[4]; + } - if (fs_type.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", - name); - } - if (partition_type.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", - name); - } - if (location.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", - name); - } - if (mount_point.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", - name); - } + if (fs_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name); + } + if (partition_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", + name); + } + if (location.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name); + } + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", + name); + } - { - char *secontext = NULL; + { + char* secontext = nullptr; - if (sehandle) { - selabel_lookup(sehandle, &secontext, mount_point.c_str(), 0755); - setfscreatecon(secontext); - } + if (sehandle) { + selabel_lookup(sehandle, &secontext, mount_point.c_str(), 0755); + setfscreatecon(secontext); + } - mkdir(mount_point.c_str(), 0755); + mkdir(mount_point.c_str(), 0755); - if (secontext) { - freecon(secontext); - setfscreatecon(NULL); - } + if (secontext) { + freecon(secontext); + setfscreatecon(nullptr); } + } - if (mount(location.c_str(), mount_point.c_str(), fs_type.c_str(), - MS_NOATIME | MS_NODEV | MS_NODIRATIME, mount_options.c_str()) < 0) { - uiPrintf(state, "%s: failed to mount %s at %s: %s\n", - name, location.c_str(), mount_point.c_str(), strerror(errno)); - return StringValue(""); - } + if (mount(location.c_str(), mount_point.c_str(), fs_type.c_str(), + MS_NOATIME | MS_NODEV | MS_NODIRATIME, mount_options.c_str()) < 0) { + uiPrintf(state, "%s: failed to mount %s at %s: %s\n", name, location.c_str(), + mount_point.c_str(), strerror(errno)); + return StringValue(""); + } - return StringValue(mount_point); + return StringValue(mount_point); } // is_mounted(mount_point) Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); - } + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& mount_point = args[0]; - if (mount_point.empty()) { - return ErrorAbort(state, kArgsParsingFailure, - "mount_point argument to unmount() can't be empty"); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& mount_point = args[0]; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "mount_point argument to unmount() can't be empty"); + } - scan_mounted_volumes(); - MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); - if (vol == nullptr) { - return StringValue(""); - } + scan_mounted_volumes(); + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); + if (vol == nullptr) { + return StringValue(""); + } - return StringValue(mount_point); + return StringValue(mount_point); } - Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); - } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& mount_point = args[0]; - if (mount_point.empty()) { - return ErrorAbort(state, kArgsParsingFailure, - "mount_point argument to unmount() can't be empty"); - } + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& mount_point = args[0]; + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, + "mount_point argument to unmount() can't be empty"); + } - scan_mounted_volumes(); - MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); - if (vol == nullptr) { - uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point.c_str()); - return nullptr; - } else { - int ret = unmount_mounted_volume(vol); - if (ret != 0) { - uiPrintf(state, "unmount of %s failed (%d): %s\n", - mount_point.c_str(), ret, strerror(errno)); - } + scan_mounted_volumes(); + MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point.c_str()); + if (vol == nullptr) { + uiPrintf(state, "unmount of %s failed; no such volume\n", mount_point.c_str()); + return nullptr; + } else { + int ret = unmount_mounted_volume(vol); + if (ret != 0) { + uiPrintf(state, "unmount of %s failed (%d): %s\n", mount_point.c_str(), ret, strerror(errno)); } + } - return StringValue(mount_point); + return StringValue(mount_point); } static int exec_cmd(const char* path, char* const argv[]) { - int status; - pid_t child; - if ((child = vfork()) == 0) { - execv(path, argv); - _exit(-1); - } - waitpid(child, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - printf("%s failed with status %d\n", path, WEXITSTATUS(status)); - } - return WEXITSTATUS(status); + pid_t child; + if ((child = vfork()) == 0) { + execv(path, argv); + _exit(-1); + } + + int status; + waitpid(child, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + LOG(ERROR) << path << " failed with status " << WEXITSTATUS(status); + } + return WEXITSTATUS(status); } // format(fs_type, partition_type, location, fs_size, mount_point) // -// fs_type="ext4" partition_type="EMMC" location=device fs_size= mount_point= -// fs_type="f2fs" partition_type="EMMC" location=device fs_size= mount_point= +// fs_type="ext4" partition_type="EMMC" location=device fs_size= mount_point= +// fs_type="f2fs" partition_type="EMMC" location=device fs_size= mount_point= // 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[]) { - if (argc != 5) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc); - } + if (argc != 5) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& fs_type = args[0]; - const std::string& partition_type = args[1]; - const std::string& location = args[2]; - const std::string& fs_size = args[3]; - const std::string& mount_point = args[4]; - - if (fs_type.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", - name); - } - if (partition_type.empty()) { - return ErrorAbort(state, kArgsParsingFailure, - "partition_type argument to %s() can't be empty", name); - } - if (location.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", - name); - } - if (mount_point.empty()) { - return ErrorAbort(state, kArgsParsingFailure, - "mount_point argument to %s() can't be empty", name); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& fs_type = args[0]; + const std::string& partition_type = args[1]; + const std::string& location = args[2]; + const std::string& fs_size = args[3]; + const std::string& mount_point = args[4]; + + if (fs_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "fs_type argument to %s() can't be empty", name); + } + if (partition_type.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "partition_type argument to %s() can't be empty", + name); + } + if (location.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "location argument to %s() can't be empty", name); + } + if (mount_point.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "mount_point argument to %s() can't be empty", + name); + } - int64_t size; - if (!android::base::ParseInt(fs_size, &size)) { - return ErrorAbort(state, kArgsParsingFailure, - "%s: failed to parse int in %s\n", name, fs_size.c_str()); + int64_t size; + if (!android::base::ParseInt(fs_size, &size)) { + return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse int in %s\n", name, + fs_size.c_str()); + } + + if (fs_type == "ext4") { + int status = make_ext4fs(location.c_str(), size, mount_point.c_str(), sehandle); + if (status != 0) { + LOG(ERROR) << name << ": make_ext4fs failed (" << status << ") on " << location; + return StringValue(""); } + return StringValue(location); + } else if (fs_type == "f2fs") { + if (size < 0) { + LOG(ERROR) << name << ": fs_size can't be negative for f2fs: " << fs_size; + return StringValue(""); + } + std::string num_sectors = std::to_string(size / 512); - if (fs_type == "ext4") { - int status = make_ext4fs(location.c_str(), size, mount_point.c_str(), sehandle); - if (status != 0) { - printf("%s: make_ext4fs failed (%d) on %s", name, status, location.c_str()); - return StringValue(""); - } - return StringValue(location); - } else if (fs_type == "f2fs") { - if (size < 0) { - printf("%s: fs_size can't be negative for f2fs: %s", name, fs_size.c_str()); - return StringValue(""); - } - std::string num_sectors = std::to_string(size / 512); - - const char *f2fs_path = "/sbin/mkfs.f2fs"; - const char* const f2fs_argv[] = {"mkfs.f2fs", "-t", "-d1", location.c_str(), - num_sectors.c_str(), nullptr}; - int status = exec_cmd(f2fs_path, (char* const*)f2fs_argv); - if (status != 0) { - printf("%s: mkfs.f2fs failed (%d) on %s", name, status, location.c_str()); - return StringValue(""); - } - return StringValue(location); - } else { - printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", - name, fs_type.c_str(), partition_type.c_str()); + const char* f2fs_path = "/sbin/mkfs.f2fs"; + const char* const f2fs_argv[] = { "mkfs.f2fs", "-t", "-d1", location.c_str(), + num_sectors.c_str(), nullptr }; + int status = exec_cmd(f2fs_path, const_cast(f2fs_argv)); + if (status != 0) { + LOG(ERROR) << name << ": mkfs.f2fs failed (" << status << ") on " << location; + return StringValue(""); } + return StringValue(location); + } else { + LOG(ERROR) << name << ": unsupported fs_type \"" << fs_type << "\" partition_type \"" + << partition_type << "\""; + } - return nullptr; + return nullptr; } // rename(src_name, dst_name) // Renames src_name to dst_name. It automatically creates the necessary directories for dst_name. // Example: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk") Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } - - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& src_name = args[0]; - const std::string& dst_name = args[1]; + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - if (src_name.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", - name); - } - if (dst_name.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", - name); - } - if (!make_parents(dst_name)) { - return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", - dst_name.c_str(), strerror(errno)); - } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { - // File was already moved - return StringValue(dst_name); - } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { - return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", - src_name.c_str(), dst_name.c_str(), strerror(errno)); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& src_name = args[0]; + const std::string& dst_name = args[1]; + if (src_name.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name); + } + if (dst_name.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); + } + if (!make_parents(dst_name)) { + return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", + dst_name.c_str(), strerror(errno)); + } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { + // File was already moved return StringValue(dst_name); + } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { + return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", + src_name.c_str(), dst_name.c_str(), strerror(errno)); + } + + return StringValue(dst_name); } // delete([filename, ...]) @@ -382,76 +375,76 @@ Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { // Recursively deletes dirnames and all their contents. Returns the number of directories // successfully deleted. Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { - std::vector paths(argc); - for (int i = 0; i < argc; ++i) { - if (!Evaluate(state, argv[i], &paths[i])) { - return nullptr; - } + std::vector paths(argc); + for (int i = 0; i < argc; ++i) { + if (!Evaluate(state, argv[i], &paths[i])) { + return nullptr; } + } - bool recursive = (strcmp(name, "delete_recursive") == 0); + bool recursive = (strcmp(name, "delete_recursive") == 0); - int success = 0; - for (int i = 0; i < argc; ++i) { - if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { - ++success; - } + int success = 0; + for (int i = 0; i < argc; ++i) { + if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { + ++success; } + } - return StringValue(std::to_string(success)); + return StringValue(std::to_string(success)); } Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } + if (argc != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& frac_str = args[0]; - const std::string& sec_str = args[1]; + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& frac_str = args[0]; + const std::string& sec_str = args[1]; - double frac; - if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { - return ErrorAbort(state, kArgsParsingFailure, - "%s: failed to parse double in %s\n", name, frac_str.c_str()); - } - int sec; - if (!android::base::ParseInt(sec_str.c_str(), &sec)) { - return ErrorAbort(state, kArgsParsingFailure, - "%s: failed to parse int in %s\n", name, sec_str.c_str()); - } + double frac; + if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { + return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse double in %s\n", name, + frac_str.c_str()); + } + int sec; + if (!android::base::ParseInt(sec_str.c_str(), &sec)) { + return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse int in %s\n", name, + sec_str.c_str()); + } - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); + UpdaterInfo* ui = static_cast(state->cookie); + fprintf(ui->cmd_pipe, "progress %f %d\n", frac, sec); - return StringValue(frac_str); + return StringValue(frac_str); } Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); - } + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& frac_str = args[0]; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& frac_str = args[0]; - double frac; - if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { - return ErrorAbort(state, kArgsParsingFailure, - "%s: failed to parse double in %s\n", name, frac_str.c_str()); - } + double frac; + if (!android::base::ParseDouble(frac_str.c_str(), &frac)) { + return ErrorAbort(state, kArgsParsingFailure, "%s: failed to parse double in %s\n", name, + frac_str.c_str()); + } - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - fprintf(ui->cmd_pipe, "set_progress %f\n", frac); + UpdaterInfo* ui = static_cast(state->cookie); + fprintf(ui->cmd_pipe, "set_progress %f\n", frac); - return StringValue(frac_str); + return StringValue(frac_str); } // package_extract_dir(package_dir, dest_dir) @@ -505,30 +498,31 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv ZipString zip_string_path(zip_path.c_str()); ZipEntry entry; if (FindEntry(za, zip_string_path, &entry) != 0) { - printf("%s: no %s in package\n", name, zip_path.c_str()); + LOG(ERROR) << name << ": no " << zip_path << " in package"; return StringValue(""); } unique_fd fd(TEMP_FAILURE_RETRY( ota_open(dest_path.c_str(), 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.c_str(), strerror(errno)); + PLOG(ERROR) << name << ": can't open " << dest_path << " for write"; return StringValue(""); } bool success = true; int32_t ret = ExtractEntryToFile(za, &entry, fd); if (ret != 0) { - printf("%s: Failed to extract entry \"%s\" (%u bytes) to \"%s\": %s\n", name, - zip_path.c_str(), entry.uncompressed_length, dest_path.c_str(), ErrorCodeString(ret)); + LOG(ERROR) << name << ": Failed to extract entry \"" << zip_path << "\" (" + << entry.uncompressed_length << " bytes) to \"" << dest_path + << "\": " << ErrorCodeString(ret); success = false; } if (ota_fsync(fd) == -1) { - printf("fsync of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + PLOG(ERROR) << "fsync of \"" << dest_path << "\" failed"; success = false; } if (ota_close(fd) == -1) { - printf("close of \"%s\" failed: %s\n", dest_path.c_str(), strerror(errno)); + PLOG(ERROR) << "close of \"" << dest_path << "\" failed"; success = false; } @@ -568,241 +562,234 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv // Creates all sources as symlinks to target. It unlinks any previously existing src1, src2, etc // before creating symlinks. 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); - } - std::string target; - if (!Evaluate(state, argv[0], &target)) { - return nullptr; - } + if (argc == 0) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1+ args, got %d", name, argc); + } + std::string target; + if (!Evaluate(state, argv[0], &target)) { + return nullptr; + } - std::vector srcs; - if (!ReadArgs(state, argc-1, argv+1, &srcs)) { - return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", - name); - } + std::vector srcs; + if (!ReadArgs(state, argc - 1, argv + 1, &srcs)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); + } - size_t bad = 0; - for (const auto& src : srcs) { - if (unlink(src.c_str()) == -1 && errno != ENOENT) { - printf("%s: failed to remove %s: %s\n", name, src.c_str(), strerror(errno)); - ++bad; - } else if (!make_parents(src)) { - printf("%s: failed to symlink %s to %s: making parents failed\n", - name, src.c_str(), target.c_str()); - ++bad; - } else if (symlink(target.c_str(), src.c_str()) == -1) { - printf("%s: failed to symlink %s to %s: %s\n", - name, src.c_str(), target.c_str(), strerror(errno)); - ++bad; - } - } - if (bad != 0) { - return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); + size_t bad = 0; + for (const auto& src : srcs) { + if (unlink(src.c_str()) == -1 && errno != ENOENT) { + PLOG(ERROR) << name << ": failed to remove " << src; + ++bad; + } else if (!make_parents(src)) { + LOG(ERROR) << name << ": failed to symlink " << src << " to " << target + << ": making parents failed"; + ++bad; + } else if (symlink(target.c_str(), src.c_str()) == -1) { + PLOG(ERROR) << name << ": failed to symlink " << src << " to " << target; + ++bad; } - return StringValue("t"); + } + if (bad != 0) { + return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); + } + return StringValue("t"); } struct perm_parsed_args { - bool has_uid; - uid_t uid; - bool has_gid; - gid_t gid; - bool has_mode; - mode_t mode; - bool has_fmode; - mode_t fmode; - bool has_dmode; - mode_t dmode; - bool has_selabel; - const char* selabel; - bool has_capabilities; - uint64_t capabilities; + bool has_uid; + uid_t uid; + bool has_gid; + gid_t gid; + bool has_mode; + mode_t mode; + bool has_fmode; + mode_t fmode; + bool has_dmode; + mode_t dmode; + bool has_selabel; + const char* selabel; + bool has_capabilities; + uint64_t capabilities; }; static struct perm_parsed_args ParsePermArgs(State * state, int argc, const std::vector& args) { - int i; - struct perm_parsed_args parsed; - int bad = 0; - static int max_warnings = 20; - - memset(&parsed, 0, sizeof(parsed)); - - for (i = 1; i < argc; i += 2) { - if (args[i] == "uid") { - int64_t uid; - if (sscanf(args[i+1].c_str(), "%" SCNd64, &uid) == 1) { - parsed.uid = uid; - parsed.has_uid = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "gid") { - int64_t gid; - if (sscanf(args[i+1].c_str(), "%" SCNd64, &gid) == 1) { - parsed.gid = gid; - parsed.has_gid = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "mode") { - int32_t mode; - if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.mode = mode; - parsed.has_mode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "dmode") { - int32_t mode; - if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.dmode = mode; - parsed.has_dmode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "fmode") { - int32_t mode; - if (sscanf(args[i+1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.fmode = mode; - parsed.has_fmode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "capabilities") { - int64_t capabilities; - if (sscanf(args[i+1].c_str(), "%" SCNi64, &capabilities) == 1) { - parsed.capabilities = capabilities; - parsed.has_capabilities = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "selabel") { - if (!args[i+1].empty()) { - parsed.selabel = args[i+1].c_str(); - parsed.has_selabel = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (max_warnings != 0) { - printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); - max_warnings--; - if (max_warnings == 0) { - printf("ParsedPermArgs: suppressing further warnings\n"); - } - } + struct perm_parsed_args parsed; + int bad = 0; + static int max_warnings = 20; + + memset(&parsed, 0, sizeof(parsed)); + + for (int i = 1; i < argc; i += 2) { + if (args[i] == "uid") { + int64_t uid; + if (sscanf(args[i + 1].c_str(), "%" SCNd64, &uid) == 1) { + parsed.uid = uid; + parsed.has_uid = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (args[i] == "gid") { + int64_t gid; + if (sscanf(args[i + 1].c_str(), "%" SCNd64, &gid) == 1) { + parsed.gid = gid; + parsed.has_gid = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (args[i] == "mode") { + int32_t mode; + if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { + parsed.mode = mode; + parsed.has_mode = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; } - return parsed; + if (args[i] == "dmode") { + int32_t mode; + if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { + parsed.dmode = mode; + parsed.has_dmode = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (args[i] == "fmode") { + int32_t mode; + if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { + parsed.fmode = mode; + parsed.has_fmode = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (args[i] == "capabilities") { + int64_t capabilities; + if (sscanf(args[i + 1].c_str(), "%" SCNi64, &capabilities) == 1) { + parsed.capabilities = capabilities; + parsed.has_capabilities = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (args[i] == "selabel") { + if (!args[i + 1].empty()) { + parsed.selabel = args[i + 1].c_str(); + parsed.has_selabel = true; + } else { + uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); + bad++; + } + continue; + } + if (max_warnings != 0) { + printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); + max_warnings--; + if (max_warnings == 0) { + LOG(INFO) << "ParsedPermArgs: suppressing further warnings"; + } + } + } + return parsed; } -static int ApplyParsedPerms( - State * state, - const char* filename, - const struct stat *statptr, - struct perm_parsed_args parsed) -{ - int bad = 0; - - if (parsed.has_selabel) { - if (lsetfilecon(filename, parsed.selabel) != 0) { - uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", - filename, parsed.selabel, strerror(errno)); - bad++; - } - } +static int ApplyParsedPerms(State* state, const char* filename, const struct stat* statptr, + struct perm_parsed_args parsed) { + int bad = 0; - /* ignore symlinks */ - if (S_ISLNK(statptr->st_mode)) { - return bad; + if (parsed.has_selabel) { + if (lsetfilecon(filename, parsed.selabel) != 0) { + uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", filename, + parsed.selabel, strerror(errno)); + bad++; } + } - if (parsed.has_uid) { - if (chown(filename, parsed.uid, -1) < 0) { - uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", - filename, parsed.uid, strerror(errno)); - bad++; - } + /* ignore symlinks */ + if (S_ISLNK(statptr->st_mode)) { + return bad; + } + + if (parsed.has_uid) { + if (chown(filename, parsed.uid, -1) < 0) { + uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", filename, parsed.uid, + strerror(errno)); + bad++; } + } - if (parsed.has_gid) { - if (chown(filename, -1, parsed.gid) < 0) { - uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", - filename, parsed.gid, strerror(errno)); - bad++; - } + if (parsed.has_gid) { + if (chown(filename, -1, parsed.gid) < 0) { + uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", filename, parsed.gid, + strerror(errno)); + bad++; } + } - if (parsed.has_mode) { - if (chmod(filename, parsed.mode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", - filename, parsed.mode, strerror(errno)); - bad++; - } + if (parsed.has_mode) { + if (chmod(filename, parsed.mode) < 0) { + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.mode, + strerror(errno)); + bad++; } + } - if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { - if (chmod(filename, parsed.dmode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", - filename, parsed.dmode, strerror(errno)); - bad++; - } + if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { + if (chmod(filename, parsed.dmode) < 0) { + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.dmode, + strerror(errno)); + bad++; } + } - if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { - if (chmod(filename, parsed.fmode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", - filename, parsed.fmode, strerror(errno)); - bad++; - } + if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { + if (chmod(filename, parsed.fmode) < 0) { + uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.fmode, + strerror(errno)); + bad++; } + } - if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { - if (parsed.capabilities == 0) { - if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { - // Report failure unless it's ENODATA (attribute not set) - uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", - filename, parsed.capabilities, strerror(errno)); - bad++; - } - } else { - struct vfs_cap_data cap_data; - memset(&cap_data, 0, sizeof(cap_data)); - cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; - cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff); - cap_data.data[0].inheritable = 0; - cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); - cap_data.data[1].inheritable = 0; - if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { - uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", - filename, parsed.capabilities, strerror(errno)); - bad++; - } - } + if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { + if (parsed.capabilities == 0) { + if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { + // Report failure unless it's ENODATA (attribute not set) + uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", filename, + parsed.capabilities, strerror(errno)); + bad++; + } + } else { + struct vfs_cap_data cap_data; + memset(&cap_data, 0, sizeof(cap_data)); + cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; + cap_data.data[0].permitted = (uint32_t)(parsed.capabilities & 0xffffffff); + cap_data.data[0].inheritable = 0; + cap_data.data[1].permitted = (uint32_t)(parsed.capabilities >> 32); + cap_data.data[1].inheritable = 0; + if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { + uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", filename, + parsed.capabilities, strerror(errno)); + bad++; + } } + } - return bad; + return bad; } // nftw doesn't allow us to pass along context, so we need to use @@ -810,60 +797,60 @@ static int ApplyParsedPerms( static struct perm_parsed_args recursive_parsed_args; static State* recursive_state; -static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, - int fileflags, struct FTW *pfwt) { - return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); +static int do_SetMetadataRecursive(const char* filename, const struct stat* statptr, int fileflags, + struct FTW* pfwt) { + return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); } static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { - if ((argc % 2) != 1) { - return ErrorAbort(state, kArgsParsingFailure, - "%s() expects an odd number of arguments, got %d", name, argc); - } + if ((argc % 2) != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects an odd number of arguments, got %d", + name, argc); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } - struct stat sb; - if (lstat(args[0].c_str(), &sb) == -1) { - return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", - name, args[0].c_str(), strerror(errno)); - } + struct stat sb; + if (lstat(args[0].c_str(), &sb) == -1) { + return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", name, + args[0].c_str(), strerror(errno)); + } - struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); - int bad = 0; - bool recursive = (strcmp(name, "set_metadata_recursive") == 0); + struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); + int bad = 0; + bool recursive = (strcmp(name, "set_metadata_recursive") == 0); - if (recursive) { - recursive_parsed_args = parsed; - recursive_state = state; - bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); - memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); - recursive_state = NULL; - } else { - bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); - } + if (recursive) { + recursive_parsed_args = parsed; + recursive_state = state; + bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); + memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + recursive_state = NULL; + } else { + bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); + } - if (bad > 0) { - return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); - } + if (bad > 0) { + return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); + } - return StringValue(""); + 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); - } - std::string key; - if (!Evaluate(state, argv[0], &key)) { - return nullptr; - } - std::string value = android::base::GetProperty(key, ""); + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } + std::string key; + if (!Evaluate(state, argv[0], &key)) { + return nullptr; + } + std::string value = android::base::GetProperty(key, ""); - return StringValue(value); + return StringValue(value); } // file_getprop(file, key) @@ -936,25 +923,34 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } // apply_patch_space(bytes) -Value* ApplyPatchSpaceFn(const char* name, State* state, - int argc, Expr* argv[]) { - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& bytes_str = args[0]; +Value* ApplyPatchSpaceFn(const char* name, State* state, int argc, Expr* argv[]) { + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& bytes_str = args[0]; - size_t bytes; - if (!android::base::ParseUint(bytes_str.c_str(), &bytes)) { - return ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n", - name, bytes_str.c_str()); - } + size_t bytes; + if (!android::base::ParseUint(bytes_str.c_str(), &bytes)) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): can't parse \"%s\" as byte count\n\n", + name, bytes_str.c_str()); + } - return StringValue(CacheSizeCheck(bytes) ? "" : "t"); + return StringValue(CacheSizeCheck(bytes) ? "" : "t"); } -// apply_patch(file, size, init_sha1, tgt_sha1, patch) - +// apply_patch(src_file, tgt_file, tgt_sha1, tgt_size, patch1_sha1, patch1_blob, [...]) +// Applies a binary patch to the src_file to produce the tgt_file. If the desired target is the +// same as the source, pass "-" for tgt_file. tgt_sha1 and tgt_size are the expected final SHA1 +// hash and size of the target file. The remaining arguments must come in pairs: a SHA1 hash (a +// 40-character hex string) and a blob. The blob is the patch to be applied when the source +// file's current contents have the given SHA1. +// +// The patching is done in a safe manner that guarantees the target file either has the desired +// SHA1 hash and size, or it is untouched -- it will not be left in an unrecoverable intermediate +// state. If the process is interrupted during patching, the target file may be in an intermediate +// state; a copy exists in the cache partition so restarting the update can successfully update +// the file. Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc < 6 || (argc % 2) == 1) { return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 6 args and an " @@ -1007,87 +1003,90 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(result == 0 ? "t" : ""); } -// apply_patch_check(file, [sha1_1, ...]) -Value* ApplyPatchCheckFn(const char* name, State* state, - int argc, Expr* argv[]) { - if (argc < 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %d", - name, argc); - } +// apply_patch_check(filename, [sha1, ...]) +// Returns true if the contents of filename or the temporary copy in the cache partition (if +// present) have a SHA-1 checksum equal to one of the given sha1 values. sha1 values are +// specified as 40 hex digits. This function differs from sha1_check(read_file(filename), +// sha1 [, ...]) in that it knows to check the cache partition copy, so apply_patch_check() will +// succeed even if the file was corrupted by an interrupted apply_patch() update. +Value* ApplyPatchCheckFn(const char* name, State* state, int argc, Expr* argv[]) { + if (argc < 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %d", name, + argc); + } - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; - std::vector sha1s; - if (!ReadArgs(state, argc - 1, argv + 1, &sha1s)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - int result = applypatch_check(filename.c_str(), sha1s); + std::vector sha1s; + if (!ReadArgs(state, argc - 1, argv + 1, &sha1s)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + int result = applypatch_check(filename.c_str(), sha1s); - return StringValue(result == 0 ? "t" : ""); + return StringValue(result == 0 ? "t" : ""); } // This is the updater side handler for ui_print() in edify script. Contents // will be sent over to the recovery side for on-screen display. Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } - std::string buffer = android::base::Join(args, "") + "\n"; - uiPrint(state, buffer); - return StringValue(buffer); + std::string buffer = android::base::Join(args, "") + "\n"; + uiPrint(state, buffer); + return StringValue(buffer); } Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); - } - fprintf(((UpdaterInfo*)(state->cookie))->cmd_pipe, "wipe_cache\n"); - return StringValue("t"); + if (argc != 0) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); + } + fprintf(static_cast(state->cookie)->cmd_pipe, "wipe_cache\n"); + return StringValue("t"); } Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); - } + if (argc < 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); + } - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } - char* args2[argc+1]; - for (int i = 0; i < argc; i++) { - args2[i] = &args[i][0]; - } - args2[argc] = nullptr; + char* args2[argc + 1]; + for (int i = 0; i < argc; i++) { + args2[i] = &args[i][0]; + } + args2[argc] = nullptr; - printf("about to run program [%s] with %d args\n", args2[0], argc); + LOG(INFO) << "about to run program [" << args2[0] << "] with " << argc << " args"; - pid_t child = fork(); - if (child == 0) { - execv(args2[0], args2); - printf("run_program: execv failed: %s\n", strerror(errno)); - _exit(1); - } - int status; - waitpid(child, &status, 0); - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) != 0) { - printf("run_program: child exited with status %d\n", - WEXITSTATUS(status)); - } - } else if (WIFSIGNALED(status)) { - printf("run_program: child terminated by signal %d\n", - WTERMSIG(status)); + pid_t child = fork(); + if (child == 0) { + execv(args2[0], args2); + PLOG(ERROR) << "run_program: execv failed"; + _exit(1); + } + + int status; + waitpid(child, &status, 0); + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + LOG(ERROR) << "run_program: child exited with status " << WEXITSTATUS(status); } + } else if (WIFSIGNALED(status)) { + LOG(ERROR) << "run_program: child terminated by signal " << WTERMSIG(status); + } - return StringValue(android::base::StringPrintf("%d", status)); + return StringValue(std::to_string(status)); } // sha1_check(data) @@ -1099,63 +1098,63 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { // strings passed, or "" if it does not equal any of them. // Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); - } + if (argc < 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); + } - std::vector> args; - if (!ReadValueArgs(state, argc, argv, &args)) { - return nullptr; - } + std::vector> args; + if (!ReadValueArgs(state, argc, argv, &args)) { + return nullptr; + } - if (args[0]->type == VAL_INVALID) { - return StringValue(""); - } - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(args[0]->data.c_str()), args[0]->data.size(), digest); + if (args[0]->type == VAL_INVALID) { + return StringValue(""); + } + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(args[0]->data.c_str()), args[0]->data.size(), digest); - if (argc == 1) { - return StringValue(print_sha1(digest)); - } + if (argc == 1) { + return StringValue(print_sha1(digest)); + } - 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.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.c_str()); - } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) { - // Found a match. - return args[i].release(); - } + for (int i = 1; i < argc; ++i) { + uint8_t arg_digest[SHA_DIGEST_LENGTH]; + if (args[i]->type != VAL_STRING) { + LOG(ERROR) << name << "(): arg " << i << " is not a string; skipping"; + } else if (ParseSha1(args[i]->data.c_str(), arg_digest) != 0) { + // Warn about bad args and skip them. + LOG(ERROR) << name << "(): error parsing \"" << args[i]->data << "\" as sha-1; skipping"; + } else if (memcmp(digest, arg_digest, SHA_DIGEST_LENGTH) == 0) { + // Found a match. + return args[i].release(); } + } - // Didn't match any of the hex strings; return false. - return StringValue(""); + // Didn't match any of the hex strings; return false. + return StringValue(""); } // Read a local file and return its contents (the Value* returned // is actually a FileContents*). Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); - } + if (argc != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); + } - std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& filename = args[0]; + std::vector args; + if (!ReadArgs(state, 1, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); + } + const std::string& filename = args[0]; - Value* v = new Value(VAL_INVALID, ""); + Value* v = new Value(VAL_INVALID, ""); - FileContents fc; - if (LoadFileContents(filename.c_str(), &fc) == 0) { - v->type = VAL_BLOB; - v->data = std::string(fc.data.begin(), fc.data.end()); - } - return v; + FileContents fc; + if (LoadFileContents(filename.c_str(), &fc) == 0) { + v->type = VAL_BLOB; + v->data = std::string(fc.data.begin(), fc.data.end()); + } + return v; } // write_value(value, filename) @@ -1178,7 +1177,7 @@ Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) { const std::string& value = args[0]; if (!android::base::WriteStringToFile(value, filename)) { - printf("%s: Failed to write to \"%s\": %s\n", name, filename.c_str(), strerror(errno)); + PLOG(ERROR) << name << ": Failed to write to \"" << filename << "\""; return StringValue(""); } else { return StringValue("t"); @@ -1210,12 +1209,12 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { bootloader_message boot; std::string err; if (!read_bootloader_message_from(&boot, filename, &err)) { - printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + LOG(ERROR) << name << "(): Failed to read from \"" << filename << "\": " << err; return StringValue(""); } memset(boot.command, 0, sizeof(boot.command)); if (!write_bootloader_message_to(boot, filename, &err)) { - printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str()); + LOG(ERROR) << name << "(): Failed to write to \"" << filename << "\": " << err; return StringValue(""); } @@ -1255,12 +1254,12 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { bootloader_message boot; std::string err; if (!read_bootloader_message_from(&boot, filename, &err)) { - printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + LOG(ERROR) << name << "(): Failed to read from \"" << filename << "\": " << err; return StringValue(""); } strlcpy(boot.stage, stagestr.c_str(), sizeof(boot.stage)); if (!write_bootloader_message_to(boot, filename, &err)) { - printf("%s(): Failed to write to \"%s\": %s", name, filename.c_str(), err.c_str()); + LOG(ERROR) << name << "(): Failed to write to \"" << filename << "\": " << err; return StringValue(""); } @@ -1283,7 +1282,7 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { bootloader_message boot; std::string err; if (!read_bootloader_message_from(&boot, filename, &err)) { - printf("%s(): Failed to read from \"%s\": %s", name, filename.c_str(), err.c_str()); + LOG(ERROR) << name << "(): Failed to read from \"" << filename << "\": " << err; return StringValue(""); } @@ -1314,93 +1313,94 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) } Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); - } - UpdaterInfo* ui = (UpdaterInfo*)(state->cookie); - fprintf(ui->cmd_pipe, "enable_reboot\n"); - return StringValue("t"); + if (argc != 0) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); + } + UpdaterInfo* ui = static_cast(state->cookie); + fprintf(ui->cmd_pipe, "enable_reboot\n"); + return StringValue("t"); } Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc == 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %d", name, argc); - } - - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name); - } + if (argc == 0) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %d", name, argc); + } - char* args2[argc+1]; - // Tune2fs expects the program name as its args[0] - args2[0] = const_cast(name); - if (args2[0] == nullptr) { - return nullptr; - } - for (int i = 0; i < argc; ++i) { - args2[i + 1] = &args[i][0]; - } + std::vector args; + if (!ReadArgs(state, argc, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name); + } - // tune2fs changes the file system parameters on an ext2 file system; it - // returns 0 on success. - int result = tune2fs_main(argc + 1, args2); + char* args2[argc + 1]; + // Tune2fs expects the program name as its args[0] + args2[0] = const_cast(name); + if (args2[0] == nullptr) { + return nullptr; + } + for (int i = 0; i < argc; ++i) { + args2[i + 1] = &args[i][0]; + } - if (result != 0) { - return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result); - } - return StringValue("t"); + // tune2fs changes the file system parameters on an ext2 file system; it + // returns 0 on success. + int result = tune2fs_main(argc + 1, args2); + if (result != 0) { + return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result); + } + return StringValue("t"); } void RegisterInstallFunctions() { - RegisterFunction("mount", MountFn); - RegisterFunction("is_mounted", IsMountedFn); - RegisterFunction("unmount", UnmountFn); - RegisterFunction("format", FormatFn); - RegisterFunction("show_progress", ShowProgressFn); - RegisterFunction("set_progress", SetProgressFn); - RegisterFunction("delete", DeleteFn); - RegisterFunction("delete_recursive", DeleteFn); - RegisterFunction("package_extract_dir", PackageExtractDirFn); - RegisterFunction("package_extract_file", PackageExtractFileFn); - RegisterFunction("symlink", SymlinkFn); - - // Usage: - // set_metadata("filename", "key1", "value1", "key2", "value2", ...) - // Example: - // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); - RegisterFunction("set_metadata", SetMetadataFn); - - // Usage: - // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) - // Example: - // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); - RegisterFunction("set_metadata_recursive", SetMetadataFn); - - RegisterFunction("getprop", GetPropFn); - RegisterFunction("file_getprop", FileGetPropFn); - - RegisterFunction("apply_patch", ApplyPatchFn); - RegisterFunction("apply_patch_check", ApplyPatchCheckFn); - RegisterFunction("apply_patch_space", ApplyPatchSpaceFn); - - RegisterFunction("wipe_block_device", WipeBlockDeviceFn); - - RegisterFunction("read_file", ReadFileFn); - RegisterFunction("sha1_check", Sha1CheckFn); - RegisterFunction("rename", RenameFn); - RegisterFunction("write_value", WriteValueFn); - - RegisterFunction("wipe_cache", WipeCacheFn); - - RegisterFunction("ui_print", UIPrintFn); - - RegisterFunction("run_program", RunProgramFn); - - RegisterFunction("reboot_now", RebootNowFn); - RegisterFunction("get_stage", GetStageFn); - RegisterFunction("set_stage", SetStageFn); - - RegisterFunction("enable_reboot", EnableRebootFn); - RegisterFunction("tune2fs", Tune2FsFn); + RegisterFunction("mount", MountFn); + RegisterFunction("is_mounted", IsMountedFn); + RegisterFunction("unmount", UnmountFn); + RegisterFunction("format", FormatFn); + RegisterFunction("show_progress", ShowProgressFn); + RegisterFunction("set_progress", SetProgressFn); + RegisterFunction("delete", DeleteFn); + RegisterFunction("delete_recursive", DeleteFn); + RegisterFunction("package_extract_dir", PackageExtractDirFn); + RegisterFunction("package_extract_file", PackageExtractFileFn); + RegisterFunction("symlink", SymlinkFn); + + // Usage: + // set_metadata("filename", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", + // "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata", SetMetadataFn); + + // Usage: + // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, + // "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata_recursive", SetMetadataFn); + + RegisterFunction("getprop", GetPropFn); + RegisterFunction("file_getprop", FileGetPropFn); + + RegisterFunction("apply_patch", ApplyPatchFn); + RegisterFunction("apply_patch_check", ApplyPatchCheckFn); + RegisterFunction("apply_patch_space", ApplyPatchSpaceFn); + + RegisterFunction("wipe_block_device", WipeBlockDeviceFn); + + RegisterFunction("read_file", ReadFileFn); + RegisterFunction("sha1_check", Sha1CheckFn); + RegisterFunction("rename", RenameFn); + RegisterFunction("write_value", WriteValueFn); + + RegisterFunction("wipe_cache", WipeCacheFn); + + RegisterFunction("ui_print", UIPrintFn); + + RegisterFunction("run_program", RunProgramFn); + + RegisterFunction("reboot_now", RebootNowFn); + RegisterFunction("get_stage", GetStageFn); + RegisterFunction("set_stage", SetStageFn); + + RegisterFunction("enable_reboot", EnableRebootFn); + RegisterFunction("tune2fs", Tune2FsFn); } diff --git a/updater/updater.cpp b/updater/updater.cpp index 7327c52e3..3e624dae7 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -23,6 +23,7 @@ #include +#include #include #include #include @@ -42,174 +43,178 @@ // Where in the package we expect to find the edify script to execute. // (Note it's "updateR-script", not the older "update-script".) -#define SCRIPT_NAME "META-INF/com/google/android/updater-script" +static constexpr const char* SCRIPT_NAME = "META-INF/com/google/android/updater-script"; extern bool have_eio_error; struct selabel_handle *sehandle; -int main(int argc, char** argv) { - // Various things log information to stdout or stderr more or less - // at random (though we've tried to standardize on stdout). The - // log file makes more sense if buffering is turned off so things - // appear in the right order. - setbuf(stdout, NULL); - setbuf(stderr, NULL); - - if (argc != 4 && argc != 5) { - printf("unexpected number of arguments (%d)\n", argc); - return 1; - } - - char* version = argv[1]; - if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || - version[1] != '\0') { - // We support version 1, 2, or 3. - printf("wrong updater binary API; expected 1, 2, or 3; " - "got %s\n", - argv[1]); - return 2; - } - - // Set up the pipe for sending commands back to the parent process. - - int fd = atoi(argv[2]); - FILE* cmd_pipe = fdopen(fd, "wb"); - setlinebuf(cmd_pipe); - - // Extract the script from the package. - - const char* package_filename = argv[3]; - MemMapping map; - if (sysMapFile(package_filename, &map) != 0) { - printf("failed to map package %s\n", argv[3]); - return 3; - } - 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], ErrorCodeString(open_err)); - CloseArchive(za); - return 3; - } - 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; - } - - std::string script; - script.resize(script_entry.uncompressed_length); - int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast(&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; - } - - // Configure edify's functions. - - RegisterBuiltins(); - RegisterInstallFunctions(); - RegisterBlockImageFunctions(); - RegisterDeviceExtensions(); - - // Parse the script. - - Expr* root; - int error_count = 0; - 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; - } - - struct selinux_opt seopts[] = { - { SELABEL_OPT_PATH, "/file_contexts" } - }; - - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); +static void UpdaterLogger(android::base::LogId /* id */, android::base::LogSeverity /* severity */, + const char* /* tag */, const char* /* file */, unsigned int /* line */, + const char* message) { + fprintf(stdout, "%s\n", message); +} - if (!sehandle) { - fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); +int main(int argc, char** argv) { + // Various things log information to stdout or stderr more or less + // at random (though we've tried to standardize on stdout). The + // log file makes more sense if buffering is turned off so things + // appear in the right order. + setbuf(stdout, nullptr); + setbuf(stderr, nullptr); + + // We don't have logcat yet under recovery. Update logs will always be written to stdout + // (which is redirected to recovery.log). + android::base::InitLogging(argv, &UpdaterLogger); + + if (argc != 4 && argc != 5) { + LOG(ERROR) << "unexpected number of arguments: " << argc; + return 1; + } + + char* version = argv[1]; + if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || version[1] != '\0') { + // We support version 1, 2, or 3. + LOG(ERROR) << "wrong updater binary API; expected 1, 2, or 3; got " << argv[1]; + return 2; + } + + // Set up the pipe for sending commands back to the parent process. + + int fd = atoi(argv[2]); + FILE* cmd_pipe = fdopen(fd, "wb"); + setlinebuf(cmd_pipe); + + // Extract the script from the package. + + const char* package_filename = argv[3]; + MemMapping map; + if (sysMapFile(package_filename, &map) != 0) { + LOG(ERROR) << "failed to map package " << argv[3]; + return 3; + } + ZipArchiveHandle za; + int open_err = OpenArchiveFromMemory(map.addr, map.length, argv[3], &za); + if (open_err != 0) { + LOG(ERROR) << "failed to open package " << argv[3] << ": " << ErrorCodeString(open_err); + CloseArchive(za); + return 3; + } + 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) { + LOG(ERROR) << "failed to find " << SCRIPT_NAME << " in " << package_filename << ": " + << ErrorCodeString(find_err); + CloseArchive(za); + return 4; + } + + std::string script; + script.resize(script_entry.uncompressed_length); + int extract_err = ExtractToMemory(za, &script_entry, reinterpret_cast(&script[0]), + script_entry.uncompressed_length); + if (extract_err != 0) { + LOG(ERROR) << "failed to read script from package: " << ErrorCodeString(extract_err); + CloseArchive(za); + return 5; + } + + // Configure edify's functions. + + RegisterBuiltins(); + RegisterInstallFunctions(); + RegisterBlockImageFunctions(); + RegisterDeviceExtensions(); + + // Parse the script. + + Expr* root; + int error_count = 0; + int error = parse_string(script.c_str(), &root, &error_count); + if (error != 0 || error_count > 0) { + LOG(ERROR) << error_count << " parse errors"; + CloseArchive(za); + return 6; + } + + struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; + + sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + + if (!sehandle) { + fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); + } + + // Evaluate the parsed script. + + UpdaterInfo updater_info; + updater_info.cmd_pipe = cmd_pipe; + 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(script, &updater_info); + + if (argc == 5) { + if (strcmp(argv[4], "retry") == 0) { + state.is_retry = true; + } else { + printf("unexpected argument: %s", argv[4]); } + } - // Evaluate the parsed script. + std::string result; + bool status = Evaluate(&state, root, &result); - UpdaterInfo updater_info; - updater_info.cmd_pipe = cmd_pipe; - updater_info.package_zip = za; - updater_info.version = atoi(version); - updater_info.package_zip_addr = map.addr; - updater_info.package_zip_len = map.length; + if (have_eio_error) { + fprintf(cmd_pipe, "retry_update\n"); + } - State state(script, &updater_info); - - if (argc == 5) { - if (strcmp(argv[4], "retry") == 0) { - state.is_retry = true; - } else { - printf("unexpected argument: %s", argv[4]); + if (!status) { + if (state.errmsg.empty()) { + LOG(ERROR) << "script aborted (no error message)"; + fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); + } else { + LOG(ERROR) << "script aborted: " << state.errmsg; + const std::vector 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.empty() && line[0] == 'E') { + if (sscanf(line.c_str(), "E%u: ", &state.error_code) != 1) { + LOG(ERROR) << "Failed to parse error code: [" << line << "]"; + } } + fprintf(cmd_pipe, "ui_print %s\n", line.c_str()); + } + fprintf(cmd_pipe, "ui_print\n"); } - std::string result; - bool status = Evaluate(&state, root, &result); - - if (have_eio_error) { - fprintf(cmd_pipe, "retry_update\n"); - } - - 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.c_str()); - const std::vector 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.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.c_str()); - } - fprintf(cmd_pipe, "ui_print\n"); - } - - if (state.error_code != kNoError) { - fprintf(cmd_pipe, "log error: %d\n", state.error_code); - // Cause code should provide additional information about the abort; - // report only when an error exists. - if (state.cause_code != kNoCause) { - fprintf(cmd_pipe, "log cause: %d\n", state.cause_code); - } - } - - 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.c_str()); + if (state.error_code != kNoError) { + fprintf(cmd_pipe, "log error: %d\n", state.error_code); + // Cause code should provide additional information about the abort; + // report only when an error exists. + if (state.cause_code != kNoCause) { + fprintf(cmd_pipe, "log cause: %d\n", state.cause_code); + } } if (updater_info.package_zip) { - CloseArchive(updater_info.package_zip); + CloseArchive(updater_info.package_zip); } - sysReleaseMap(&map); + return 7; + } else { + fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result.c_str()); + } + + if (updater_info.package_zip) { + CloseArchive(updater_info.package_zip); + } + sysReleaseMap(&map); - return 0; + return 0; } -- cgit v1.2.3 From 5354f60f2bdb8c7341534c9cb6a27cc218c48f87 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 14 Dec 2016 11:31:18 -0800 Subject: updater: Fix the operator order. Shift operator ("<<") has a higher precedence level than ternary operator ("?"). Test: BBOTA update log says "performing update" as opposed to "performing 0". Change-Id: I0cf60cbfc11415e94f1f9f6effe75f14d13a1874 --- updater/blockimg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 7257e2399..4dadceb5e 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1358,7 +1358,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg CommandParameters params = {}; params.canwrite = !dryrun; - LOG(INFO) << "performing " << dryrun ? "verification" : "update"; + LOG(INFO) << "performing " << (dryrun ? "verification" : "update"); if (state->is_retry) { is_retry = true; LOG(INFO) << "This update is a retry."; -- cgit v1.2.3 From 0d3f84f237b2fab810de1438f7207b1763ad4011 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 28 Dec 2016 15:09:20 -0800 Subject: updater: Update the header name for bootloader.h. We should include "bootloader_message/bootloader_message.h" now. Test: m updater Change-Id: I65b22a8a0bcc5976ff1ba827bd30b46ee9d59c53 --- updater/install.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 3cf38774e..643145447 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include #include @@ -54,8 +56,6 @@ #include #include -#include "applypatch/applypatch.h" -#include "bootloader.h" #include "edify/expr.h" #include "error_code.h" #include "mounts.h" -- cgit v1.2.3 From 514122121147181de5850e83ea0f09d791d5d720 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 28 Dec 2016 14:44:05 -0800 Subject: updater: Clean up CreateStash(). Change the stash size computation from int to size_t. Test: Apply an incremental BBOTA with the new updater. Change-Id: Ib45b71b826fec6aa0ffafc67c17735825634eae0 --- updater/blockimg.cpp | 169 ++++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 84 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 4dadceb5e..696c1bba4 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -41,27 +41,26 @@ #include #include #include +#include +#include #include -#include "applypatch/applypatch.h" #include "edify/expr.h" #include "error_code.h" #include "updater/install.h" -#include "openssl/sha.h" #include "ota_io.h" #include "print_sha1.h" #include "updater/updater.h" -static constexpr size_t BLOCKSIZE = 4096; - // Set this to 0 to interpret 'erase' transfers to mean do a // BLKDISCARD ioctl (the normal behavior). Set to 1 to interpret // erase to mean fill the region with zeroes. #define DEBUG_ERASE 0 -#define STASH_DIRECTORY_BASE "/cache/recovery" -#define STASH_DIRECTORY_MODE 0700 -#define STASH_FILE_MODE 0600 +static constexpr size_t BLOCKSIZE = 4096; +static constexpr const char* STASH_DIRECTORY_BASE = "/cache/recovery"; +static constexpr mode_t STASH_DIRECTORY_MODE = 0700; +static constexpr mode_t STASH_FILE_MODE = 0600; struct RangeSet { size_t count; // Limit is INT_MAX. @@ -509,18 +508,18 @@ static void EnumerateStash(const std::string& dirname, StashCallback callback, v } static void UpdateFileSize(const std::string& fn, void* data) { - if (fn.empty() || !data) { - return; - } + if (fn.empty() || !data) { + return; + } - struct stat sb; - if (stat(fn.c_str(), &sb) == -1) { - PLOG(ERROR) << "stat \"" << fn << "\" failed"; - return; - } + struct stat sb; + if (stat(fn.c_str(), &sb) == -1) { + PLOG(ERROR) << "stat \"" << fn << "\" failed"; + return; + } - int* size = reinterpret_cast(data); - *size += sb.st_size; + size_t* size = static_cast(data); + *size += sb.st_size; } // Deletes the stash directory and all files in it. Assumes that it only @@ -710,63 +709,67 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks // hash enough space for the expected amount of blocks we need to store. Returns // >0 if we created the directory, zero if it existed already, and <0 of failure. -static int CreateStash(State* state, int maxblocks, const char* blockdev, std::string& base) { - if (blockdev == nullptr) { - return -1; - } - - // Stash directory should be different for each partition to avoid conflicts - // when updating multiple partitions at the same time, so we use the hash of - // the block device name as the base directory - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(blockdev), strlen(blockdev), digest); - base = print_sha1(digest); - - std::string dirname = GetStashFileName(base, "", ""); - struct stat sb; - int res = stat(dirname.c_str(), &sb); - - if (res == -1 && errno != ENOENT) { - ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n", - dirname.c_str(), strerror(errno)); - return -1; - } else if (res != 0) { - LOG(INFO) << "creating stash " << dirname; - res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE); - - if (res != 0) { - ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n", - dirname.c_str(), strerror(errno)); - return -1; - } +static int CreateStash(State* state, size_t maxblocks, const std::string& blockdev, + std::string& base) { + if (blockdev.empty()) { + return -1; + } + + // Stash directory should be different for each partition to avoid conflicts + // when updating multiple partitions at the same time, so we use the hash of + // the block device name as the base directory + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(reinterpret_cast(blockdev.data()), blockdev.size(), digest); + base = print_sha1(digest); + + std::string dirname = GetStashFileName(base, "", ""); + struct stat sb; + int res = stat(dirname.c_str(), &sb); + size_t max_stash_size = maxblocks * BLOCKSIZE; + + if (res == -1 && errno != ENOENT) { + ErrorAbort(state, kStashCreationFailure, "stat \"%s\" failed: %s\n", dirname.c_str(), + strerror(errno)); + return -1; + } else if (res != 0) { + LOG(INFO) << "creating stash " << dirname; + res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE); - if (CacheSizeCheck(maxblocks * BLOCKSIZE) != 0) { - ErrorAbort(state, kStashCreationFailure, "not enough space for stash\n"); - return -1; - } + if (res != 0) { + ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s\n", dirname.c_str(), + strerror(errno)); + return -1; + } - return 1; // Created directory + if (CacheSizeCheck(max_stash_size) != 0) { + ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu needed)\n", + max_stash_size); + return -1; } - LOG(INFO) << "using existing stash " << dirname; + return 1; // Created directory + } - // If the directory already exists, calculate the space already allocated to - // stash files and check if there's enough for all required blocks. Delete any - // partially completed stash files first. + LOG(INFO) << "using existing stash " << dirname; - EnumerateStash(dirname, DeletePartial, nullptr); - int size = 0; - EnumerateStash(dirname, UpdateFileSize, &size); + // If the directory already exists, calculate the space already allocated to + // stash files and check if there's enough for all required blocks. Delete any + // partially completed stash files first. - size = maxblocks * BLOCKSIZE - size; + EnumerateStash(dirname, DeletePartial, nullptr); + size_t existing = 0; + EnumerateStash(dirname, UpdateFileSize, &existing); - if (size > 0 && CacheSizeCheck(size) != 0) { - ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%d more needed)\n", - size); - return -1; + if (max_stash_size > existing) { + size_t needed = max_stash_size - existing; + if (CacheSizeCheck(needed) != 0) { + ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu more needed)\n", + needed); + return -1; } + } - return 0; // Using existing directory + return 0; // Using existing directory } static int SaveStash(CommandParameters& params, const std::string& base, @@ -1393,8 +1396,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg return StringValue(""); } - UpdaterInfo* ui = reinterpret_cast(state->cookie); - + UpdaterInfo* ui = static_cast(state->cookie); if (ui == nullptr) { return StringValue(""); } @@ -1452,7 +1454,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg } // First line in transfer list is the version number - if (!android::base::ParseInt(lines[0].c_str(), ¶ms.version, 1, 4)) { + if (!android::base::ParseInt(lines[0], ¶ms.version, 1, 4)) { LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]"; return StringValue(""); } @@ -1460,8 +1462,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg LOG(INFO) << "blockimg version is " << params.version; // Second line in transfer list is the total number of blocks we expect to write - int total_blocks; - if (!android::base::ParseInt(lines[1].c_str(), &total_blocks, 0)) { + size_t total_blocks; + if (!android::base::ParseUint(lines[1], &total_blocks)) { ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str()); return StringValue(""); } @@ -1473,23 +1475,23 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg size_t start = 2; if (params.version >= 2) { if (lines.size() < 4) { - ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", - lines.size()); - return StringValue(""); + ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", + lines.size()); + return StringValue(""); } // Third line is how many stash entries are needed simultaneously LOG(INFO) << "maximum stash entries " << lines[2]; // Fourth line is the maximum number of blocks that will be stashed simultaneously - int stash_max_blocks; - if (!android::base::ParseInt(lines[3].c_str(), &stash_max_blocks, 0)) { + size_t stash_max_blocks; + if (!android::base::ParseUint(lines[3], &stash_max_blocks)) { ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n", lines[3].c_str()); return StringValue(""); } - int res = CreateStash(state, stash_max_blocks, blockdev_filename->data.c_str(), params.stashbase); + int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase); if (res == -1) { return StringValue(""); } @@ -1514,15 +1516,13 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg // Subsequent lines are all individual transfer commands for (auto it = lines.cbegin() + start; it != lines.cend(); it++) { - const std::string& line_str(*it); - if (line_str.empty()) { - continue; - } + const std::string& line(*it); + if (line.empty()) continue; - params.tokens = android::base::Split(line_str, " "); + params.tokens = android::base::Split(line, " "); params.cpos = 0; params.cmdname = params.tokens[params.cpos++].c_str(); - params.cmdline = line_str.c_str(); + params.cmdline = line.c_str(); if (cmd_map.find(params.cmdname) == cmd_map.end()) { LOG(ERROR) << "unexpected command [" << params.cmdname << "]"; @@ -1532,7 +1532,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg const Command* cmd = cmd_map[params.cmdname]; if (cmd->f != nullptr && cmd->f(params) == -1) { - LOG(ERROR) << "failed to execute command [" << line_str << "]"; + LOG(ERROR) << "failed to execute command [" << line << "]"; goto pbiudone; } @@ -1542,7 +1542,8 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg PLOG(ERROR) << "fsync failed"; goto pbiudone; } - fprintf(cmd_pipe, "set_progress %.4f\n", (double) params.written / total_blocks); + fprintf(cmd_pipe, "set_progress %.4f\n", + static_cast(params.written) / total_blocks); fflush(cmd_pipe); } } @@ -1555,7 +1556,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg LOG(INFO) << "max alloc needed was " << params.buffer.size(); const char* partition = strrchr(blockdev_filename->data.c_str(), '/'); - if (partition != nullptr && *(partition+1) != 0) { + if (partition != nullptr && *(partition + 1) != 0) { fprintf(cmd_pipe, "log bytes_written_%s: %zu\n", partition + 1, params.written * BLOCKSIZE); fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, -- cgit v1.2.3 From c844c06faf92d2250a0f0b4ec8aab97ebfd5b747 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 28 Dec 2016 15:15:55 -0800 Subject: updater: Refactor parse_range(). Returning the parsed RangeSet directly (as opposed to using some pointer parameter) to make the code cleaner. Test: Apply an incremental with the new updater. Change-Id: I8c99e701f189eb6a3eacc0d647e5a3a85fbeb3eb --- updater/blockimg.cpp | 137 +++++++++++++++++++++++---------------------------- 1 file changed, 63 insertions(+), 74 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 4dadceb5e..03089ae41 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -64,83 +64,82 @@ static constexpr size_t BLOCKSIZE = 4096; #define STASH_FILE_MODE 0600 struct RangeSet { - size_t count; // Limit is INT_MAX. - size_t size; - std::vector pos; // Actual limit is INT_MAX. + size_t count; // Limit is INT_MAX. + size_t size; + std::vector pos; // Actual limit is INT_MAX. }; static CauseCode failure_type = kNoCause; static bool is_retry = false; static std::unordered_map stash_map; -static void parse_range(const std::string& range_text, RangeSet& rs) { +static RangeSet parse_range(const std::string& range_text) { + RangeSet rs; - std::vector pieces = android::base::Split(range_text, ","); - if (pieces.size() < 3) { - goto err; - } + std::vector pieces = android::base::Split(range_text, ","); + if (pieces.size() < 3) { + goto err; + } - size_t num; - if (!android::base::ParseUint(pieces[0].c_str(), &num, static_cast(INT_MAX))) { - goto err; - } + size_t num; + if (!android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) { + goto err; + } - if (num == 0 || num % 2) { - goto err; // must be even - } else if (num != pieces.size() - 1) { - goto err; - } + if (num == 0 || num % 2) { + goto err; // must be even + } else if (num != pieces.size() - 1) { + goto err; + } - rs.pos.resize(num); - rs.count = num / 2; - rs.size = 0; - - for (size_t i = 0; i < num; i += 2) { - if (!android::base::ParseUint(pieces[i+1].c_str(), &rs.pos[i], - static_cast(INT_MAX))) { - goto err; - } + rs.pos.resize(num); + rs.count = num / 2; + rs.size = 0; - if (!android::base::ParseUint(pieces[i+2].c_str(), &rs.pos[i+1], - static_cast(INT_MAX))) { - goto err; - } + for (size_t i = 0; i < num; i += 2) { + if (!android::base::ParseUint(pieces[i + 1], &rs.pos[i], static_cast(INT_MAX))) { + goto err; + } - if (rs.pos[i] >= rs.pos[i+1]) { - goto err; // empty or negative range - } + if (!android::base::ParseUint(pieces[i + 2], &rs.pos[i + 1], static_cast(INT_MAX))) { + goto err; + } - size_t sz = rs.pos[i+1] - rs.pos[i]; - if (rs.size > SIZE_MAX - sz) { - goto err; // overflow - } + if (rs.pos[i] >= rs.pos[i + 1]) { + goto err; // empty or negative range + } - rs.size += sz; + size_t sz = rs.pos[i + 1] - rs.pos[i]; + if (rs.size > SIZE_MAX - sz) { + goto err; // overflow } - return; + rs.size += sz; + } + + return rs; err: - LOG(ERROR) << "failed to parse range '" << range_text << "'"; - exit(1); + LOG(ERROR) << "failed to parse range '" << range_text << "'"; + exit(1); } static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) { - for (size_t i = 0; i < r1.count; ++i) { - size_t r1_0 = r1.pos[i * 2]; - size_t r1_1 = r1.pos[i * 2 + 1]; + for (size_t i = 0; i < r1.count; ++i) { + size_t r1_0 = r1.pos[i * 2]; + size_t r1_1 = r1.pos[i * 2 + 1]; - for (size_t j = 0; j < r2.count; ++j) { - size_t r2_0 = r2.pos[j * 2]; - size_t r2_1 = r2.pos[j * 2 + 1]; + for (size_t j = 0; j < r2.count; ++j) { + size_t r2_0 = r2.pos[j * 2]; + size_t r2_1 = r2.pos[j * 2 + 1]; - if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) { - return true; - } - } + if (!(r2_0 >= r1_1 || r1_0 >= r2_1)) { + return true; + } } + } - return false; + return false; } static int read_all(int fd, uint8_t* data, size_t size) { @@ -431,11 +430,10 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& } // - RangeSet src; - parse_range(params.tokens[params.cpos++], src); + RangeSet src = parse_range(params.tokens[params.cpos++]); // - parse_range(params.tokens[params.cpos++], tgt); + tgt = parse_range(params.tokens[params.cpos++]); allocate(src.size * BLOCKSIZE, buffer); int rc = ReadBlocks(src, buffer, fd); @@ -787,8 +785,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } - RangeSet src; - parse_range(params.tokens[params.cpos++], src); + RangeSet src = parse_range(params.tokens[params.cpos++]); allocate(src.size * BLOCKSIZE, buffer); if (ReadBlocks(src, buffer, fd) == -1) { @@ -872,7 +869,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } // - parse_range(params.tokens[params.cpos++], tgt); + tgt = parse_range(params.tokens[params.cpos++]); // const std::string& token = params.tokens[params.cpos++]; @@ -888,8 +885,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& // no source ranges, only stashes params.cpos++; } else { - RangeSet src; - parse_range(params.tokens[params.cpos++], src); + RangeSet src = parse_range(params.tokens[params.cpos++]); int res = ReadBlocks(src, buffer, fd); if (overlap) { @@ -905,8 +901,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& return 0; } - RangeSet locs; - parse_range(params.tokens[params.cpos++], locs); + RangeSet locs = parse_range(params.tokens[params.cpos++]); MoveRange(buffer, locs, buffer); } @@ -931,8 +926,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& continue; } - RangeSet locs; - parse_range(tokens[1], locs); + RangeSet locs = parse_range(tokens[1]); MoveRange(buffer, locs, stash); } @@ -1116,8 +1110,7 @@ static int PerformCommandZero(CommandParameters& params) { return -1; } - RangeSet tgt; - parse_range(params.tokens[params.cpos++], tgt); + RangeSet tgt = parse_range(params.tokens[params.cpos++]); LOG(INFO) << " zeroing " << tgt.size << " blocks"; @@ -1160,8 +1153,7 @@ static int PerformCommandNew(CommandParameters& params) { return -1; } - RangeSet tgt; - parse_range(params.tokens[params.cpos++], tgt); + RangeSet tgt = parse_range(params.tokens[params.cpos++]); if (params.canwrite) { LOG(INFO) << " writing " << tgt.size << " blocks of new data"; @@ -1316,8 +1308,7 @@ static int PerformCommandErase(CommandParameters& params) { return -1; } - RangeSet tgt; - parse_range(params.tokens[params.cpos++], tgt); + RangeSet tgt = parse_range(params.tokens[params.cpos++]); if (params.canwrite) { LOG(INFO) << " erasing " << tgt.size << " blocks"; @@ -1707,8 +1698,7 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) return StringValue(""); } - RangeSet rs; - parse_range(ranges->data, rs); + RangeSet rs = parse_range(ranges->data); SHA_CTX ctx; SHA1_Init(&ctx); @@ -1832,8 +1822,7 @@ Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[ return StringValue(""); } - RangeSet rs; - parse_range(ranges->data, rs); + RangeSet rs = parse_range(ranges->data); uint8_t buffer[BLOCKSIZE]; -- cgit v1.2.3 From 4728242070ce806828024f00ab3dac6ba48f3206 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 9 Jan 2017 13:45:37 -0800 Subject: Do not inject I/O fault on a retry We could inject I/O faults during an OTA update for test purpose. But we should skip the injection if the update is an retry. Otherwise the update test will simply keeps failing. Bug: 34159970 Test: Apply the same package on angler and the update succeeds on the 2nd try. Change-Id: Id274e5475e3bc8d25d50a8cf61a77d2e32c569d6 --- updater/updater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index 3e624dae7..473066263 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -100,7 +100,6 @@ int main(int argc, char** argv) { CloseArchive(za); return 3; } - ota_io_init(za); ZipString script_name(SCRIPT_NAME); ZipEntry script_entry; @@ -166,6 +165,7 @@ int main(int argc, char** argv) { printf("unexpected argument: %s", argv[4]); } } + ota_io_init(za, state.is_retry); std::string result; bool status = Evaluate(&state, root, &result); -- cgit v1.2.3 From 31653660adad6aa220f1a975545042126ee83b84 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Wed, 11 Jan 2017 14:02:13 -0800 Subject: Remove "_static" suffix from libext4_utils. Bug: 34220783 Change-Id: I34ccc3b11da0d1b48805967ad75b9ddade569930 --- updater/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 5d328a3fa..22c73241a 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -31,7 +31,7 @@ updater_common_static_libraries := \ libutils \ libmounts \ libotafault \ - libext4_utils_static \ + libext4_utils \ libfec \ libfec_rs \ libfs_mgr \ -- cgit v1.2.3 From 67f3aa880499c1143ed9aa1e5294a912a6962f28 Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Wed, 11 Jan 2017 14:38:20 -0800 Subject: Remove "_static" suffix from libsparse Bug: 34220783 Change-Id: I358f931f0b29f5bd526e1475180e477e2e90b936 --- updater/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 22c73241a..d8a84c248 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -37,7 +37,7 @@ updater_common_static_libraries := \ libfs_mgr \ liblog \ libselinux \ - libsparse_static \ + libsparse \ libsquashfs_utils \ libbz \ libz \ -- cgit v1.2.3 From f013642477dbe0a5ed8d440571e9c8676ed42b2d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 21 Jan 2017 13:03:25 -0800 Subject: Print with newline for ui_print. Currently the ui_print command between the recovery and updater doesn't append newline. Updater has to send an extra "ui_print" command without any argument to get the line break. This looks unnecessary. And not all the callers (including the ones in bootable/recovery) are following this protocol when sending the ui_print command. This CL simplifies the protocol to always print with a newline for ui_print command. When updating from an old recovery with the new updater, all the ui_print'd strings would appear in one line as a side effect. But a) it would only affect the text-mode UI, which won't be shown to users; b) log files won't be affected. Bug: 32305035 Test: Apply an update with the new updater on top of an old and new recovery image respectively. Change-Id: I305a0ffc6f180daf60919cf99d24d1495d68749b --- updater/install.cpp | 1 - updater/updater.cpp | 1 - 2 files changed, 2 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index 643145447..7a8e92f6c 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -76,7 +76,6 @@ static void uiPrint(State* state, const std::string& buffer) { for (auto& line : lines) { if (!line.empty()) { fprintf(ui->cmd_pipe, "ui_print %s\n", line.c_str()); - fprintf(ui->cmd_pipe, "ui_print\n"); } } diff --git a/updater/updater.cpp b/updater/updater.cpp index 473066263..22c060fcb 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -191,7 +191,6 @@ int main(int argc, char** argv) { } fprintf(cmd_pipe, "ui_print %s\n", line.c_str()); } - fprintf(cmd_pipe, "ui_print\n"); } if (state.error_code != kNoError) { -- cgit v1.2.3 From 7c5dbd67517b4c96455617ed59628e1de0b3fcbb Mon Sep 17 00:00:00 2001 From: Alex Deymo Date: Fri, 13 Jan 2017 17:32:20 -0800 Subject: Remove '_static' suffix from libext2* references. Bug: 34220783 Test: make checkbuild Change-Id: Iceea20e440a4bb6a3b254486a65a86401a2241ef --- updater/Android.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index d8a84c248..ac26bf42d 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -18,7 +18,7 @@ tune2fs_static_libraries := \ libext2_com_err \ libext2_blkid \ libext2_quota \ - libext2_uuid_static \ + libext2_uuid \ libext2_e2p \ libext2fs -- cgit v1.2.3 From 25c56979dd85a33a6467949ab76f99a987a0a006 Mon Sep 17 00:00:00 2001 From: Sen Jiang Date: Tue, 10 May 2016 15:23:25 -0700 Subject: Use bspatch from external/bsdiff. Now ApplyBSDiffPatch() will stream the output to sink as we go instead of sinking everything at the end. Test: recovery_host_test Bug: 26982501 Change-Id: I05b6ed40d45e4b1b19ae72784cf705b731b976e3 --- updater/Android.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index ac26bf42d..3a47dacd5 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -24,6 +24,7 @@ tune2fs_static_libraries := \ updater_common_static_libraries := \ libapplypatch \ + libbspatch \ libedify \ libziparchive \ libotautil \ -- cgit v1.2.3 From 3da880156b4a56a6af5065ac10dfd6833cdcb1d4 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 3 Feb 2017 13:09:23 -0800 Subject: Replace _exit(-1) with _exit(EXIT_FAILURE). -1 is not a valid exit status. Also replace a few exit(1) with exit(EXIT_FAILURE). Test: mmma bootable/recovery Change-Id: I4596c8328b770bf95acccc06a4401bd5cabd4bfd --- updater/blockimg.cpp | 2 +- updater/install.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 6755d78cb..03ce4136e 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -120,7 +120,7 @@ static RangeSet parse_range(const std::string& range_text) { err: LOG(ERROR) << "failed to parse range '" << range_text << "'"; - exit(1); + exit(EXIT_FAILURE); } static bool range_overlaps(const RangeSet& r1, const RangeSet& r2) { diff --git a/updater/install.cpp b/updater/install.cpp index 7a8e92f6c..c7ecdb5c7 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -247,7 +247,7 @@ static int exec_cmd(const char* path, char* const argv[]) { pid_t child; if ((child = vfork()) == 0) { execv(path, argv); - _exit(-1); + _exit(EXIT_FAILURE); } int status; @@ -1072,7 +1072,7 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { if (child == 0) { execv(args2[0], args2); PLOG(ERROR) << "run_program: execv failed"; - _exit(1); + _exit(EXIT_FAILURE); } int status; -- cgit v1.2.3 From 63d786cf22cb44fe32e8b9c1f18b32da3c9d2e1b Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 8 Mar 2017 16:42:20 -0800 Subject: updater: Remove some obsoleted functions for file-based OTA. This CL removes the updater support for delete(), symlink(), rename(), set_metadata() and set_metadata_recursive(). Such functions have been removed from the generation script in commit f388104eaacd05cfa075d6478369e1d0df5ddbf3 (platform/build). Note: This CL also removes delete_recursive() which seems to have never been supported in generation script. Bug: 35853185 Test: recovery_component_test passes. Change-Id: I51e1ec946fa73761118fa1eaa082423df6d588e9 --- updater/install.cpp | 362 ---------------------------------------------------- 1 file changed, 362 deletions(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index c7ecdb5c7..0963333fc 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -332,68 +332,6 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; } -// rename(src_name, dst_name) -// Renames src_name to dst_name. It automatically creates the necessary directories for dst_name. -// Example: rename("system/app/Hangouts/Hangouts.apk", "system/priv-app/Hangouts/Hangouts.apk") -Value* RenameFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); - } - - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - const std::string& src_name = args[0]; - const std::string& dst_name = args[1]; - - if (src_name.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "src_name argument to %s() can't be empty", name); - } - if (dst_name.empty()) { - return ErrorAbort(state, kArgsParsingFailure, "dst_name argument to %s() can't be empty", name); - } - if (!make_parents(dst_name)) { - return ErrorAbort(state, kFileRenameFailure, "Creating parent of %s failed, error %s", - dst_name.c_str(), strerror(errno)); - } else if (access(dst_name.c_str(), F_OK) == 0 && access(src_name.c_str(), F_OK) != 0) { - // File was already moved - return StringValue(dst_name); - } else if (rename(src_name.c_str(), dst_name.c_str()) != 0) { - return ErrorAbort(state, kFileRenameFailure, "Rename of %s to %s failed, error %s", - src_name.c_str(), dst_name.c_str(), strerror(errno)); - } - - return StringValue(dst_name); -} - -// delete([filename, ...]) -// Deletes all the filenames listed. Returns the number of files successfully deleted. -// -// delete_recursive([dirname, ...]) -// Recursively deletes dirnames and all their contents. Returns the number of directories -// successfully deleted. -Value* DeleteFn(const char* name, State* state, int argc, Expr* argv[]) { - std::vector paths(argc); - for (int i = 0; i < argc; ++i) { - if (!Evaluate(state, argv[i], &paths[i])) { - return nullptr; - } - } - - bool recursive = (strcmp(name, "delete_recursive") == 0); - - int success = 0; - for (int i = 0; i < argc; ++i) { - if ((recursive ? dirUnlinkHierarchy(paths[i].c_str()) : unlink(paths[i].c_str())) == 0) { - ++success; - } - } - - return StringValue(std::to_string(success)); -} - - Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 2) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); @@ -557,288 +495,6 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv } } -// symlink(target, [src1, src2, ...]) -// Creates all sources as symlinks to target. It unlinks any previously existing src1, src2, etc -// before creating symlinks. -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); - } - std::string target; - if (!Evaluate(state, argv[0], &target)) { - return nullptr; - } - - std::vector srcs; - if (!ReadArgs(state, argc - 1, argv + 1, &srcs)) { - return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); - } - - size_t bad = 0; - for (const auto& src : srcs) { - if (unlink(src.c_str()) == -1 && errno != ENOENT) { - PLOG(ERROR) << name << ": failed to remove " << src; - ++bad; - } else if (!make_parents(src)) { - LOG(ERROR) << name << ": failed to symlink " << src << " to " << target - << ": making parents failed"; - ++bad; - } else if (symlink(target.c_str(), src.c_str()) == -1) { - PLOG(ERROR) << name << ": failed to symlink " << src << " to " << target; - ++bad; - } - } - if (bad != 0) { - return ErrorAbort(state, kSymlinkFailure, "%s: Failed to create %zu symlink(s)", name, bad); - } - return StringValue("t"); -} - -struct perm_parsed_args { - bool has_uid; - uid_t uid; - bool has_gid; - gid_t gid; - bool has_mode; - mode_t mode; - bool has_fmode; - mode_t fmode; - bool has_dmode; - mode_t dmode; - bool has_selabel; - const char* selabel; - bool has_capabilities; - uint64_t capabilities; -}; - -static struct perm_parsed_args ParsePermArgs(State * state, int argc, - const std::vector& args) { - struct perm_parsed_args parsed; - int bad = 0; - static int max_warnings = 20; - - memset(&parsed, 0, sizeof(parsed)); - - for (int i = 1; i < argc; i += 2) { - if (args[i] == "uid") { - int64_t uid; - if (sscanf(args[i + 1].c_str(), "%" SCNd64, &uid) == 1) { - parsed.uid = uid; - parsed.has_uid = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid UID \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "gid") { - int64_t gid; - if (sscanf(args[i + 1].c_str(), "%" SCNd64, &gid) == 1) { - parsed.gid = gid; - parsed.has_gid = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid GID \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "mode") { - int32_t mode; - if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.mode = mode; - parsed.has_mode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid mode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "dmode") { - int32_t mode; - if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.dmode = mode; - parsed.has_dmode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "fmode") { - int32_t mode; - if (sscanf(args[i + 1].c_str(), "%" SCNi32, &mode) == 1) { - parsed.fmode = mode; - parsed.has_fmode = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "capabilities") { - int64_t capabilities; - if (sscanf(args[i + 1].c_str(), "%" SCNi64, &capabilities) == 1) { - parsed.capabilities = capabilities; - parsed.has_capabilities = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (args[i] == "selabel") { - if (!args[i + 1].empty()) { - parsed.selabel = args[i + 1].c_str(); - parsed.has_selabel = true; - } else { - uiPrintf(state, "ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1].c_str()); - bad++; - } - continue; - } - if (max_warnings != 0) { - printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i].c_str()); - max_warnings--; - if (max_warnings == 0) { - LOG(INFO) << "ParsedPermArgs: suppressing further warnings"; - } - } - } - return parsed; -} - -static int ApplyParsedPerms(State* state, const char* filename, const struct stat* statptr, - struct perm_parsed_args parsed) { - int bad = 0; - - if (parsed.has_selabel) { - if (lsetfilecon(filename, parsed.selabel) != 0) { - uiPrintf(state, "ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", filename, - parsed.selabel, strerror(errno)); - bad++; - } - } - - /* ignore symlinks */ - if (S_ISLNK(statptr->st_mode)) { - return bad; - } - - if (parsed.has_uid) { - if (chown(filename, parsed.uid, -1) < 0) { - uiPrintf(state, "ApplyParsedPerms: chown of %s to %d failed: %s\n", filename, parsed.uid, - strerror(errno)); - bad++; - } - } - - if (parsed.has_gid) { - if (chown(filename, -1, parsed.gid) < 0) { - uiPrintf(state, "ApplyParsedPerms: chgrp of %s to %d failed: %s\n", filename, parsed.gid, - strerror(errno)); - bad++; - } - } - - if (parsed.has_mode) { - if (chmod(filename, parsed.mode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.mode, - strerror(errno)); - bad++; - } - } - - if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { - if (chmod(filename, parsed.dmode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.dmode, - strerror(errno)); - bad++; - } - } - - if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { - if (chmod(filename, parsed.fmode) < 0) { - uiPrintf(state, "ApplyParsedPerms: chmod of %s to %d failed: %s\n", filename, parsed.fmode, - strerror(errno)); - bad++; - } - } - - if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { - if (parsed.capabilities == 0) { - if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { - // Report failure unless it's ENODATA (attribute not set) - uiPrintf(state, "ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", filename, - parsed.capabilities, strerror(errno)); - bad++; - } - } else { - struct vfs_cap_data cap_data; - memset(&cap_data, 0, sizeof(cap_data)); - cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; - cap_data.data[0].permitted = (uint32_t)(parsed.capabilities & 0xffffffff); - cap_data.data[0].inheritable = 0; - cap_data.data[1].permitted = (uint32_t)(parsed.capabilities >> 32); - cap_data.data[1].inheritable = 0; - if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { - uiPrintf(state, "ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", filename, - parsed.capabilities, strerror(errno)); - bad++; - } - } - } - - return bad; -} - -// nftw doesn't allow us to pass along context, so we need to use -// global variables. *sigh* -static struct perm_parsed_args recursive_parsed_args; -static State* recursive_state; - -static int do_SetMetadataRecursive(const char* filename, const struct stat* statptr, int fileflags, - struct FTW* pfwt) { - return ApplyParsedPerms(recursive_state, filename, statptr, recursive_parsed_args); -} - -static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { - if ((argc % 2) != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects an odd number of arguments, got %d", - name, argc); - } - - std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); - } - - struct stat sb; - if (lstat(args[0].c_str(), &sb) == -1) { - return ErrorAbort(state, kSetMetadataFailure, "%s: Error on lstat of \"%s\": %s", name, - args[0].c_str(), strerror(errno)); - } - - struct perm_parsed_args parsed = ParsePermArgs(state, argc, args); - int bad = 0; - bool recursive = (strcmp(name, "set_metadata_recursive") == 0); - - if (recursive) { - recursive_parsed_args = parsed; - recursive_state = state; - bad += nftw(args[0].c_str(), do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); - memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); - recursive_state = NULL; - } else { - bad += ApplyParsedPerms(state, args[0].c_str(), &sb, parsed); - } - - if (bad > 0) { - return ErrorAbort(state, kSetMetadataFailure, "%s: some changes failed", name); - } - - 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); @@ -1356,25 +1012,8 @@ void RegisterInstallFunctions() { RegisterFunction("format", FormatFn); RegisterFunction("show_progress", ShowProgressFn); RegisterFunction("set_progress", SetProgressFn); - RegisterFunction("delete", DeleteFn); - RegisterFunction("delete_recursive", DeleteFn); RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); - RegisterFunction("symlink", SymlinkFn); - - // Usage: - // set_metadata("filename", "key1", "value1", "key2", "value2", ...) - // Example: - // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", - // "u:object_r:system_file:s0", "capabilities", 0x0); - RegisterFunction("set_metadata", SetMetadataFn); - - // Usage: - // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) - // Example: - // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, - // "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); - RegisterFunction("set_metadata_recursive", SetMetadataFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); @@ -1387,7 +1026,6 @@ void RegisterInstallFunctions() { RegisterFunction("read_file", ReadFileFn); RegisterFunction("sha1_check", Sha1CheckFn); - RegisterFunction("rename", RenameFn); RegisterFunction("write_value", WriteValueFn); RegisterFunction("wipe_cache", WipeCacheFn); -- cgit v1.2.3 From bb0cd75a0e1f6760bdf96bd141f3a546ffa45fbc Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Fri, 6 Jan 2017 17:46:22 -0800 Subject: Print SHA-1 in hex for corrupted blocks It will be helpful for debug if we know which blocks are corrupted after a verification failure. This CL prints the SHA-1 for each source block in a transfer command if these blocks don't have an expected hash. And along with the correct SHA-1, we will catch the corrupted blocks. Bug: 21124445 Test: Printed the mismatched SHA-1 for bullhead during an update. Change-Id: I683d4bdaf9a335035045b3f532b3a265b2fcbbfc --- updater/blockimg.cpp | 143 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 03ce4136e..c2897a83e 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -66,6 +66,21 @@ struct RangeSet { size_t count; // Limit is INT_MAX. size_t size; std::vector pos; // Actual limit is INT_MAX. + + // Get the block number for the ith(starting from 0) block in the range set. + int get_block(size_t idx) const { + if (idx >= size) { + LOG(ERROR) << "index: " << idx << " is greater than range set size: " << size; + return -1; + } + for (size_t i = 0; i < pos.size(); i += 2) { + if (idx < pos[i + 1] - pos[i]) { + return pos[i] + idx; + } + idx -= (pos[i + 1] - pos[i]); + } + return -1; + } }; static CauseCode failure_type = kNoCause; @@ -441,6 +456,117 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& return rc; } +// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is +// handled separately). +static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params, + const std::vector& buffer) { + LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline; + if (params.version < 3) { + // TODO handle version 1,2 + LOG(WARNING) << "version number " << params.version << " is not supported to print hashes"; + return; + } + + CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" || + params.tokens[0] == "imgdiff"); + + size_t pos = 0; + // Command example: + // move [ ] + // bsdiff + // [ ] + if (params.tokens[0] == "move") { + // src_range for move starts at the 4th position. + if (params.tokens.size() < 5) { + LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; + return; + } + pos = 4; + } else { + // src_range for diff starts at the 7th position. + if (params.tokens.size() < 8) { + LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; + return; + } + pos = 7; + } + + // Source blocks in stash only, no work to do. + if (params.tokens[pos] == "-") { + return; + } + + RangeSet src = parse_range(params.tokens[pos++]); + + RangeSet locs; + // If there's no stashed blocks, content in the buffer is consecutive and has the same + // order as the source blocks. + if (pos == params.tokens.size()) { + locs.count = 1; + locs.size = src.size; + locs.pos = { 0, src.size }; + } else { + // Otherwise, the next token is the offset of the source blocks in the target range. + // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> ; + // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38]; + // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978. + locs = parse_range(params.tokens[pos++]); + CHECK_EQ(src.size, locs.size); + CHECK_EQ(locs.pos.size() % 2, static_cast(0)); + } + + LOG(INFO) << "printing hash in hex for " << src.size << " source blocks"; + for (size_t i = 0; i < src.size; i++) { + int block_num = src.get_block(i); + CHECK_NE(block_num, -1); + int buffer_index = locs.get_block(i); + CHECK_NE(buffer_index, -1); + CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size()); + + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest); + std::string hexdigest = print_sha1(digest); + LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; + } +} + +// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1 +// in hex for each block. +static void PrintHashForCorruptedStashedBlocks(const std::string& id, + const std::vector& buffer, + const RangeSet& src) { + LOG(INFO) << "printing hash in hex for stash_id: " << id; + CHECK_EQ(src.size * BLOCKSIZE, buffer.size()); + + for (size_t i = 0; i < src.size; i++) { + int block_num = src.get_block(i); + CHECK_NE(block_num, -1); + + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest); + std::string hexdigest = print_sha1(digest); + LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; + } +} + +// If the stash file doesn't exist, read the source blocks this stash contains and print the +// SHA-1 for these blocks. +static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) { + if (stash_map.find(id) == stash_map.end()) { + LOG(ERROR) << "No stash saved for id: " << id; + return; + } + + LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id; + const RangeSet& src = stash_map[id]; + std::vector buffer(src.size * BLOCKSIZE); + if (ReadBlocks(src, buffer, fd) == -1) { + LOG(ERROR) << "failed to read source blocks for stash: " << id; + return; + } + PrintHashForCorruptedStashedBlocks(id, buffer, src); +} + static int VerifyBlocks(const std::string& expected, const std::vector& buffer, const size_t blocks, bool printerror) { uint8_t digest[SHA_DIGEST_LENGTH]; @@ -573,6 +699,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s } if (VerifyBlocks(id, buffer, src.size, true) != 0) { LOG(ERROR) << "failed to verify loaded source blocks in stash map."; + PrintHashForCorruptedStashedBlocks(id, buffer, src); return -1; } return 0; @@ -597,6 +724,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (res == -1) { if (errno != ENOENT || printnoent) { PLOG(ERROR) << "stat \"" << fn << "\" failed"; + PrintHashForMissingStashedBlocks(id, params.fd); } return -1; } @@ -624,6 +752,13 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) { LOG(ERROR) << "unexpected contents in " << fn; + if (stash_map.find(id) == stash_map.end()) { + LOG(ERROR) << "failed to find source blocks number for stash " << id + << " when executing command: " << params.cmdname; + } else { + const RangeSet& src = stash_map[id]; + PrintHashForCorruptedStashedBlocks(id, buffer, src); + } DeleteFile(fn, nullptr); return -1; } @@ -795,6 +930,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, return -1; } blocks = src.size; + stash_map[id] = src; if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) { // Source blocks have unexpected contents. If we actually need this @@ -805,9 +941,8 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } - // In verify mode, save source range_set instead of stashing blocks. + // In verify mode, we don't need to stash any blocks. if (!params.canwrite && usehash) { - stash_map[id] = src; return 0; } @@ -1026,6 +1161,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& // Valid source data not available, update cannot be resumed LOG(ERROR) << "partition has unexpected contents"; + PrintHashForCorruptedSourceBlocks(params, params.buffer); + params.isunresumable = true; return -1; @@ -1094,7 +1231,7 @@ static int PerformCommandFree(CommandParameters& params) { const std::string& id = params.tokens[params.cpos++]; - if (!params.canwrite && stash_map.find(id) != stash_map.end()) { + if (stash_map.find(id) != stash_map.end()) { stash_map.erase(id); return 0; } -- cgit v1.2.3 From 90eff6a340f9983792d700df3b1ea0203aced207 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Mar 2017 09:56:03 -0700 Subject: Revert "Print SHA-1 in hex for corrupted blocks" This reverts commit bb0cd75a0e1f6760bdf96bd141f3a546ffa45fbc. Broke the 'free' command that deletes a stash. Bug: 36242722 Test: The previously failed incremental applies successfully. Change-Id: I1237cb0a33adfbeea57e0465b629704862ba13aa --- updater/blockimg.cpp | 143 ++------------------------------------------------- 1 file changed, 3 insertions(+), 140 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index c2897a83e..03ce4136e 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -66,21 +66,6 @@ struct RangeSet { size_t count; // Limit is INT_MAX. size_t size; std::vector pos; // Actual limit is INT_MAX. - - // Get the block number for the ith(starting from 0) block in the range set. - int get_block(size_t idx) const { - if (idx >= size) { - LOG(ERROR) << "index: " << idx << " is greater than range set size: " << size; - return -1; - } - for (size_t i = 0; i < pos.size(); i += 2) { - if (idx < pos[i + 1] - pos[i]) { - return pos[i] + idx; - } - idx -= (pos[i + 1] - pos[i]); - } - return -1; - } }; static CauseCode failure_type = kNoCause; @@ -456,117 +441,6 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& return rc; } -// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is -// handled separately). -static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params, - const std::vector& buffer) { - LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline; - if (params.version < 3) { - // TODO handle version 1,2 - LOG(WARNING) << "version number " << params.version << " is not supported to print hashes"; - return; - } - - CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" || - params.tokens[0] == "imgdiff"); - - size_t pos = 0; - // Command example: - // move [ ] - // bsdiff - // [ ] - if (params.tokens[0] == "move") { - // src_range for move starts at the 4th position. - if (params.tokens.size() < 5) { - LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; - return; - } - pos = 4; - } else { - // src_range for diff starts at the 7th position. - if (params.tokens.size() < 8) { - LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; - return; - } - pos = 7; - } - - // Source blocks in stash only, no work to do. - if (params.tokens[pos] == "-") { - return; - } - - RangeSet src = parse_range(params.tokens[pos++]); - - RangeSet locs; - // If there's no stashed blocks, content in the buffer is consecutive and has the same - // order as the source blocks. - if (pos == params.tokens.size()) { - locs.count = 1; - locs.size = src.size; - locs.pos = { 0, src.size }; - } else { - // Otherwise, the next token is the offset of the source blocks in the target range. - // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> ; - // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38]; - // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978. - locs = parse_range(params.tokens[pos++]); - CHECK_EQ(src.size, locs.size); - CHECK_EQ(locs.pos.size() % 2, static_cast(0)); - } - - LOG(INFO) << "printing hash in hex for " << src.size << " source blocks"; - for (size_t i = 0; i < src.size; i++) { - int block_num = src.get_block(i); - CHECK_NE(block_num, -1); - int buffer_index = locs.get_block(i); - CHECK_NE(buffer_index, -1); - CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size()); - - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest); - std::string hexdigest = print_sha1(digest); - LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; - } -} - -// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1 -// in hex for each block. -static void PrintHashForCorruptedStashedBlocks(const std::string& id, - const std::vector& buffer, - const RangeSet& src) { - LOG(INFO) << "printing hash in hex for stash_id: " << id; - CHECK_EQ(src.size * BLOCKSIZE, buffer.size()); - - for (size_t i = 0; i < src.size; i++) { - int block_num = src.get_block(i); - CHECK_NE(block_num, -1); - - uint8_t digest[SHA_DIGEST_LENGTH]; - SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest); - std::string hexdigest = print_sha1(digest); - LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; - } -} - -// If the stash file doesn't exist, read the source blocks this stash contains and print the -// SHA-1 for these blocks. -static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) { - if (stash_map.find(id) == stash_map.end()) { - LOG(ERROR) << "No stash saved for id: " << id; - return; - } - - LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id; - const RangeSet& src = stash_map[id]; - std::vector buffer(src.size * BLOCKSIZE); - if (ReadBlocks(src, buffer, fd) == -1) { - LOG(ERROR) << "failed to read source blocks for stash: " << id; - return; - } - PrintHashForCorruptedStashedBlocks(id, buffer, src); -} - static int VerifyBlocks(const std::string& expected, const std::vector& buffer, const size_t blocks, bool printerror) { uint8_t digest[SHA_DIGEST_LENGTH]; @@ -699,7 +573,6 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s } if (VerifyBlocks(id, buffer, src.size, true) != 0) { LOG(ERROR) << "failed to verify loaded source blocks in stash map."; - PrintHashForCorruptedStashedBlocks(id, buffer, src); return -1; } return 0; @@ -724,7 +597,6 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (res == -1) { if (errno != ENOENT || printnoent) { PLOG(ERROR) << "stat \"" << fn << "\" failed"; - PrintHashForMissingStashedBlocks(id, params.fd); } return -1; } @@ -752,13 +624,6 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) { LOG(ERROR) << "unexpected contents in " << fn; - if (stash_map.find(id) == stash_map.end()) { - LOG(ERROR) << "failed to find source blocks number for stash " << id - << " when executing command: " << params.cmdname; - } else { - const RangeSet& src = stash_map[id]; - PrintHashForCorruptedStashedBlocks(id, buffer, src); - } DeleteFile(fn, nullptr); return -1; } @@ -930,7 +795,6 @@ static int SaveStash(CommandParameters& params, const std::string& base, return -1; } blocks = src.size; - stash_map[id] = src; if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) { // Source blocks have unexpected contents. If we actually need this @@ -941,8 +805,9 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } - // In verify mode, we don't need to stash any blocks. + // In verify mode, save source range_set instead of stashing blocks. if (!params.canwrite && usehash) { + stash_map[id] = src; return 0; } @@ -1161,8 +1026,6 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& // Valid source data not available, update cannot be resumed LOG(ERROR) << "partition has unexpected contents"; - PrintHashForCorruptedSourceBlocks(params, params.buffer); - params.isunresumable = true; return -1; @@ -1231,7 +1094,7 @@ static int PerformCommandFree(CommandParameters& params) { const std::string& id = params.tokens[params.cpos++]; - if (stash_map.find(id) != stash_map.end()) { + if (!params.canwrite && stash_map.find(id) != stash_map.end()) { stash_map.erase(id); return 0; } -- cgit v1.2.3 From ec8272f6e3a1e1697469b0f2cb7fd86a120bf3f6 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 15 Mar 2017 17:39:01 -0700 Subject: updater: Minor clean up to EnumerateStash(). Test: Apply an incremental BBOTA package with the new updater. Test: Resume an interrupted BBOTA (so it cleans up the partial stash). Change-Id: I620cc57ee6366845bcffbc19210f7a01e2196052 --- updater/blockimg.cpp | 123 +++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 73 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 03ce4136e..6227154e5 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -473,88 +474,54 @@ static std::string GetStashFileName(const std::string& base, const std::string& return fn; } -typedef void (*StashCallback)(const std::string&, void*); +// Does a best effort enumeration of stash files. Ignores possible non-file items in the stash +// directory and continues despite of errors. Calls the 'callback' function for each file. +static void EnumerateStash(const std::string& dirname, + const std::function& callback) { + if (dirname.empty()) return; -// Does a best effort enumeration of stash files. Ignores possible non-file -// items in the stash directory and continues despite of errors. Calls the -// 'callback' function for each file and passes 'data' to the function as a -// parameter. + std::unique_ptr directory(opendir(dirname.c_str()), closedir); -static void EnumerateStash(const std::string& dirname, StashCallback callback, void* data) { - if (dirname.empty() || callback == nullptr) { - return; + if (directory == nullptr) { + if (errno != ENOENT) { + PLOG(ERROR) << "opendir \"" << dirname << "\" failed"; } - - std::unique_ptr directory(opendir(dirname.c_str()), closedir); - - if (directory == nullptr) { - if (errno != ENOENT) { - PLOG(ERROR) << "opendir \"" << dirname << "\" failed"; - } - return; - } - - struct dirent* item; - while ((item = readdir(directory.get())) != nullptr) { - if (item->d_type != DT_REG) { - continue; - } - - std::string fn = dirname + "/" + std::string(item->d_name); - callback(fn, data); - } -} - -static void UpdateFileSize(const std::string& fn, void* data) { - if (fn.empty() || !data) { return; } - struct stat sb; - if (stat(fn.c_str(), &sb) == -1) { - PLOG(ERROR) << "stat \"" << fn << "\" failed"; - return; + dirent* item; + while ((item = readdir(directory.get())) != nullptr) { + if (item->d_type != DT_REG) continue; + callback(dirname + "/" + item->d_name); } - - size_t* size = static_cast(data); - *size += sb.st_size; } // Deletes the stash directory and all files in it. Assumes that it only // contains files. There is nothing we can do about unlikely, but possible // errors, so they are merely logged. +static void DeleteFile(const std::string& fn) { + if (fn.empty()) return; -static void DeleteFile(const std::string& fn, void* /* data */) { - if (!fn.empty()) { - LOG(INFO) << "deleting " << fn; - - if (unlink(fn.c_str()) == -1 && errno != ENOENT) { - PLOG(ERROR) << "unlink \"" << fn << "\" failed"; - } - } -} + LOG(INFO) << "deleting " << fn; -static void DeletePartial(const std::string& fn, void* data) { - if (android::base::EndsWith(fn, ".partial")) { - DeleteFile(fn, data); - } + if (unlink(fn.c_str()) == -1 && errno != ENOENT) { + PLOG(ERROR) << "unlink \"" << fn << "\" failed"; + } } static void DeleteStash(const std::string& base) { - if (base.empty()) { - return; - } + if (base.empty()) return; - LOG(INFO) << "deleting stash " << base; + LOG(INFO) << "deleting stash " << base; - std::string dirname = GetStashFileName(base, "", ""); - EnumerateStash(dirname, DeleteFile, nullptr); + std::string dirname = GetStashFileName(base, "", ""); + EnumerateStash(dirname, DeleteFile); - if (rmdir(dirname.c_str()) == -1) { - if (errno != ENOENT && errno != ENOTDIR) { - PLOG(ERROR) << "rmdir \"" << dirname << "\" failed"; - } + if (rmdir(dirname.c_str()) == -1) { + if (errno != ENOENT && errno != ENOTDIR) { + PLOG(ERROR) << "rmdir \"" << dirname << "\" failed"; } + } } static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id, @@ -624,7 +591,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) { LOG(ERROR) << "unexpected contents in " << fn; - DeleteFile(fn, nullptr); + DeleteFile(fn); return -1; } @@ -750,13 +717,24 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& blockd LOG(INFO) << "using existing stash " << dirname; - // If the directory already exists, calculate the space already allocated to - // stash files and check if there's enough for all required blocks. Delete any - // partially completed stash files first. + // If the directory already exists, calculate the space already allocated to stash files and check + // if there's enough for all required blocks. Delete any partially completed stash files first. + EnumerateStash(dirname, [](const std::string& fn) { + if (android::base::EndsWith(fn, ".partial")) { + DeleteFile(fn); + } + }); - EnumerateStash(dirname, DeletePartial, nullptr); size_t existing = 0; - EnumerateStash(dirname, UpdateFileSize, &existing); + EnumerateStash(dirname, [&existing](const std::string& fn) { + if (fn.empty()) return; + struct stat sb; + if (stat(fn.c_str(), &sb) == -1) { + PLOG(ERROR) << "stat \"" << fn << "\" failed"; + return; + } + existing += static_cast(sb.st_size); + }); if (max_stash_size > existing) { size_t needed = max_stash_size - existing; @@ -817,14 +795,13 @@ static int SaveStash(CommandParameters& params, const std::string& base, } static int FreeStash(const std::string& base, const std::string& id) { - if (base.empty() || id.empty()) { - return -1; - } + if (base.empty() || id.empty()) { + return -1; + } - std::string fn = GetStashFileName(base, id, ""); - DeleteFile(fn, nullptr); + DeleteFile(GetStashFileName(base, id, "")); - return 0; + return 0; } static void MoveRange(std::vector& dest, const RangeSet& locs, -- cgit v1.2.3 From 2cd36ba52265c824e226378bdcfc66969411c1b0 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Wed, 15 Mar 2017 23:52:46 +0000 Subject: Revert "Revert "Print SHA-1 in hex for corrupted blocks"" This reverts commit 90eff6a340f9983792d700df3b1ea0203aced207. Also fix the bug where stashed blocks are not freed. Bug: 21124445 Test: Previous failed update succeeded on bullhead Change-Id: I23d232331a2beb51b6dcc82c957c87bc247d0268 --- updater/blockimg.cpp | 146 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 6 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 6227154e5..0fa83d9d5 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -67,6 +67,21 @@ struct RangeSet { size_t count; // Limit is INT_MAX. size_t size; std::vector pos; // Actual limit is INT_MAX. + + // Get the block number for the ith(starting from 0) block in the range set. + int get_block(size_t idx) const { + if (idx >= size) { + LOG(ERROR) << "index: " << idx << " is greater than range set size: " << size; + return -1; + } + for (size_t i = 0; i < pos.size(); i += 2) { + if (idx < pos[i + 1] - pos[i]) { + return pos[i] + idx; + } + idx -= (pos[i + 1] - pos[i]); + } + return -1; + } }; static CauseCode failure_type = kNoCause; @@ -442,6 +457,117 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& return rc; } +// Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is +// handled separately). +static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params, + const std::vector& buffer) { + LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline; + if (params.version < 3) { + // TODO handle version 1,2 + LOG(WARNING) << "version number " << params.version << " is not supported to print hashes"; + return; + } + + CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" || + params.tokens[0] == "imgdiff"); + + size_t pos = 0; + // Command example: + // move [ ] + // bsdiff + // [ ] + if (params.tokens[0] == "move") { + // src_range for move starts at the 4th position. + if (params.tokens.size() < 5) { + LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; + return; + } + pos = 4; + } else { + // src_range for diff starts at the 7th position. + if (params.tokens.size() < 8) { + LOG(ERROR) << "failed to parse source range in cmd:\n" << params.cmdline; + return; + } + pos = 7; + } + + // Source blocks in stash only, no work to do. + if (params.tokens[pos] == "-") { + return; + } + + RangeSet src = parse_range(params.tokens[pos++]); + + RangeSet locs; + // If there's no stashed blocks, content in the buffer is consecutive and has the same + // order as the source blocks. + if (pos == params.tokens.size()) { + locs.count = 1; + locs.size = src.size; + locs.pos = { 0, src.size }; + } else { + // Otherwise, the next token is the offset of the source blocks in the target range. + // Example: for the tokens <4,63946,63947,63948,63979> <4,6,7,8,39> ; + // We want to print SHA-1 for the data in buffer[6], buffer[8], buffer[9] ... buffer[38]; + // this corresponds to the 32 src blocks #63946, #63948, #63949 ... #63978. + locs = parse_range(params.tokens[pos++]); + CHECK_EQ(src.size, locs.size); + CHECK_EQ(locs.pos.size() % 2, static_cast(0)); + } + + LOG(INFO) << "printing hash in hex for " << src.size << " source blocks"; + for (size_t i = 0; i < src.size; i++) { + int block_num = src.get_block(i); + CHECK_NE(block_num, -1); + int buffer_index = locs.get_block(i); + CHECK_NE(buffer_index, -1); + CHECK_LE((buffer_index + 1) * BLOCKSIZE, buffer.size()); + + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(buffer.data() + buffer_index * BLOCKSIZE, BLOCKSIZE, digest); + std::string hexdigest = print_sha1(digest); + LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; + } +} + +// If the calculated hash for the whole stash doesn't match the stash id, print the SHA-1 +// in hex for each block. +static void PrintHashForCorruptedStashedBlocks(const std::string& id, + const std::vector& buffer, + const RangeSet& src) { + LOG(INFO) << "printing hash in hex for stash_id: " << id; + CHECK_EQ(src.size * BLOCKSIZE, buffer.size()); + + for (size_t i = 0; i < src.size; i++) { + int block_num = src.get_block(i); + CHECK_NE(block_num, -1); + + uint8_t digest[SHA_DIGEST_LENGTH]; + SHA1(buffer.data() + i * BLOCKSIZE, BLOCKSIZE, digest); + std::string hexdigest = print_sha1(digest); + LOG(INFO) << " block number: " << block_num << ", SHA-1: " << hexdigest; + } +} + +// If the stash file doesn't exist, read the source blocks this stash contains and print the +// SHA-1 for these blocks. +static void PrintHashForMissingStashedBlocks(const std::string& id, int fd) { + if (stash_map.find(id) == stash_map.end()) { + LOG(ERROR) << "No stash saved for id: " << id; + return; + } + + LOG(INFO) << "print hash in hex for source blocks in missing stash: " << id; + const RangeSet& src = stash_map[id]; + std::vector buffer(src.size * BLOCKSIZE); + if (ReadBlocks(src, buffer, fd) == -1) { + LOG(ERROR) << "failed to read source blocks for stash: " << id; + return; + } + PrintHashForCorruptedStashedBlocks(id, buffer, src); +} + static int VerifyBlocks(const std::string& expected, const std::vector& buffer, const size_t blocks, bool printerror) { uint8_t digest[SHA_DIGEST_LENGTH]; @@ -540,6 +666,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s } if (VerifyBlocks(id, buffer, src.size, true) != 0) { LOG(ERROR) << "failed to verify loaded source blocks in stash map."; + PrintHashForCorruptedStashedBlocks(id, buffer, src); return -1; } return 0; @@ -564,6 +691,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (res == -1) { if (errno != ENOENT || printnoent) { PLOG(ERROR) << "stat \"" << fn << "\" failed"; + PrintHashForMissingStashedBlocks(id, params.fd); } return -1; } @@ -591,6 +719,13 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s if (verify && VerifyBlocks(id, buffer, *blocks, true) != 0) { LOG(ERROR) << "unexpected contents in " << fn; + if (stash_map.find(id) == stash_map.end()) { + LOG(ERROR) << "failed to find source blocks number for stash " << id + << " when executing command: " << params.cmdname; + } else { + const RangeSet& src = stash_map[id]; + PrintHashForCorruptedStashedBlocks(id, buffer, src); + } DeleteFile(fn); return -1; } @@ -773,6 +908,7 @@ static int SaveStash(CommandParameters& params, const std::string& base, return -1; } blocks = src.size; + stash_map[id] = src; if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) { // Source blocks have unexpected contents. If we actually need this @@ -783,9 +919,8 @@ static int SaveStash(CommandParameters& params, const std::string& base, return 0; } - // In verify mode, save source range_set instead of stashing blocks. + // In verify mode, we don't need to stash any blocks. if (!params.canwrite && usehash) { - stash_map[id] = src; return 0; } @@ -1003,6 +1138,8 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& // Valid source data not available, update cannot be resumed LOG(ERROR) << "partition has unexpected contents"; + PrintHashForCorruptedSourceBlocks(params, params.buffer); + params.isunresumable = true; return -1; @@ -1071,9 +1208,8 @@ static int PerformCommandFree(CommandParameters& params) { const std::string& id = params.tokens[params.cpos++]; - if (!params.canwrite && stash_map.find(id) != stash_map.end()) { + if (stash_map.find(id) != stash_map.end()) { stash_map.erase(id); - return 0; } if (params.createdstash || params.canwrite) { @@ -1215,10 +1351,8 @@ static int PerformCommandDiff(CommandParameters& params) { if (params.canwrite) { if (status == 0) { LOG(INFO) << "patching " << blocks << " blocks to " << tgt.size; - Value patch_value(VAL_BLOB, std::string(reinterpret_cast(params.patch_start + offset), len)); - RangeSinkState rss(tgt); rss.fd = params.fd; rss.p_block = 0; -- cgit v1.2.3 From edec27a5bd08ff2779d980dc5fa7b8b7dca34fa0 Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Tue, 21 Mar 2017 16:41:14 -0700 Subject: Fix updater include generation w/installclean Since this was putting the intermediate file in obj/PACKAGING, every installclean was removing it and triggering updater to rebuild. Instead, use the standard generated-sources-dir. The dep file can also be removed now that ninja will re-run the generator if the command line changes. Test: m -j updater; m installclean; m -j updater Test: Only change to aosp_fugu updater before/after is the debug info Change-Id: I20928bd2049d4a3d4e21f83fd64d16cfdc541958 --- updater/Android.mk | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'updater') diff --git a/updater/Android.mk b/updater/Android.mk index 3a47dacd5..a113fe86c 100644 --- a/updater/Android.mk +++ b/updater/Android.mk @@ -110,21 +110,11 @@ LOCAL_STATIC_LIBRARIES := \ # any subsidiary static libraries required for your registered # extension libs. -inc := $(call intermediates-dir-for,PACKAGING,updater_extensions)/register.inc - -# Encode the value of TARGET_RECOVERY_UPDATER_LIBS into the filename of the dependency. -# So if TARGET_RECOVERY_UPDATER_LIBS is changed, a new dependency file will be generated. -# Note that we have to remove any existing depency files before creating new one, -# so no obsolete dependecy file gets used if you switch back to an old value. -inc_dep_file := $(inc).dep.$(subst $(space),-,$(sort $(TARGET_RECOVERY_UPDATER_LIBS))) -$(inc_dep_file): stem := $(inc).dep -$(inc_dep_file) : - $(hide) mkdir -p $(dir $@) - $(hide) rm -f $(stem).* - $(hide) touch $@ +LOCAL_MODULE_CLASS := EXECUTABLES +inc := $(call local-generated-sources-dir)/register.inc $(inc) : libs := $(TARGET_RECOVERY_UPDATER_LIBS) -$(inc) : $(inc_dep_file) +$(inc) : $(hide) mkdir -p $(dir $@) $(hide) echo "" > $@ $(hide) $(foreach lib,$(libs),echo "extern void Register_$(lib)(void);" >> $@;) @@ -132,11 +122,9 @@ $(inc) : $(inc_dep_file) $(hide) $(foreach lib,$(libs),echo " Register_$(lib)();" >> $@;) $(hide) echo "}" >> $@ -$(call intermediates-dir-for,EXECUTABLES,updater,,,$(TARGET_PREFER_32_BIT))/updater.o : $(inc) -LOCAL_C_INCLUDES += $(dir $(inc)) +LOCAL_GENERATED_SOURCES := $(inc) inc := -inc_dep_file := LOCAL_FORCE_STATIC_EXECUTABLE := true -- cgit v1.2.3 From a946b9e2419e0d7f29a52a047c70857eb9251cbd Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 21 Mar 2017 16:24:57 -0700 Subject: Fix the permission of stashed blocks created by updater Our updater created the stashes with root permission. This causes an access denial when the RecoverySystem service tries to clean up these blocks after a failing update. As a result, the subsequent OTA updates may fail due to insufficient cache space. Bug: 36457133 Test: stashed blocks cleaned successfully after reboot Change-Id: If0ca99638cdfa1033646f29d9cc92b5ff1bacac1 --- updater/blockimg.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 0fa83d9d5..8dbd8c7d1 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include "edify/expr.h" @@ -772,6 +773,11 @@ static int WriteStash(const std::string& base, const std::string& id, int blocks return -1; } + if (fchown(fd, AID_SYSTEM, AID_SYSTEM) != 0) { // system user + PLOG(ERROR) << "failed to chown \"" << fn << "\""; + return -1; + } + if (write_all(fd, buffer, blocks * BLOCKSIZE) == -1) { return -1; } @@ -841,6 +847,12 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& blockd return -1; } + if (chown(dirname.c_str(), AID_SYSTEM, AID_SYSTEM) != 0) { // system user + ErrorAbort(state, kStashCreationFailure, "chown \"%s\" failed: %s\n", dirname.c_str(), + strerror(errno)); + return -1; + } + if (CacheSizeCheck(max_stash_size) != 0) { ErrorAbort(state, kStashCreationFailure, "not enough space for stash (%zu needed)\n", max_stash_size); -- cgit v1.2.3 From c444732540d5245b6219293e96d29f325daa7839 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Mon, 6 Mar 2017 14:44:59 -0800 Subject: Remove malloc in edify functions And switch them to std::vector & std::unique_ptr Bug: 32117870 Test: recovery tests passed on sailfish Change-Id: I5a45951c4bdf895be311d6d760e52e7a1b0798c3 --- updater/blockimg.cpp | 54 +++++++++--- updater/install.cpp | 242 ++++++++++++++++++++++++++++----------------------- updater/updater.cpp | 2 +- 3 files changed, 173 insertions(+), 125 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 8dbd8c7d1..efdfec19a 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1470,8 +1470,9 @@ struct Command { // - new data stream (filename within package.zip) // - patch stream (filename within package.zip, must be uncompressed) -static Value* PerformBlockImageUpdate(const char* name, State* state, int /* argc */, Expr* argv[], - const Command* commands, size_t cmdcount, bool dryrun) { +static Value* PerformBlockImageUpdate(const char* name, State* state, + const std::vector>& argv, + const Command* commands, size_t cmdcount, bool dryrun) { CommandParameters params = {}; params.canwrite = !dryrun; @@ -1480,9 +1481,14 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg is_retry = true; LOG(INFO) << "This update is a retry."; } + if (argv.size() != 4) { + ErrorAbort(state, kArgsParsingFailure, "block_image_update expects 4 arguments, got %zu", + argv.size()); + return StringValue(""); + } std::vector> args; - if (!ReadValueArgs(state, 4, argv, &args)) { + if (!ReadValueArgs(state, argv, &args)) { return nullptr; } @@ -1762,7 +1768,8 @@ pbiudone: // command has already been completed and verify the integrity of // the source data. -Value* BlockImageVerifyFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* BlockImageVerifyFn(const char* name, State* state, + const std::vector>& argv) { // Commands which are not tested are set to nullptr to skip them completely const Command commands[] = { { "bsdiff", PerformCommandDiff }, @@ -1776,11 +1783,12 @@ Value* BlockImageVerifyFn(const char* name, State* state, int argc, Expr* argv[] }; // Perform a dry run without writing to test if an update can proceed - return PerformBlockImageUpdate(name, state, argc, argv, commands, + return PerformBlockImageUpdate(name, state, argv, commands, sizeof(commands) / sizeof(commands[0]), true); } -Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* BlockImageUpdateFn(const char* name, State* state, + const std::vector>& argv) { const Command commands[] = { { "bsdiff", PerformCommandDiff }, { "erase", PerformCommandErase }, @@ -1792,13 +1800,19 @@ Value* BlockImageUpdateFn(const char* name, State* state, int argc, Expr* argv[] { "zero", PerformCommandZero } }; - return PerformBlockImageUpdate(name, state, argc, argv, commands, + return PerformBlockImageUpdate(name, state, argv, commands, sizeof(commands) / sizeof(commands[0]), false); } -Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) { +Value* RangeSha1Fn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + ErrorAbort(state, kArgsParsingFailure, "range_sha1 expects 2 arguments, got %zu", + argv.size()); + return StringValue(""); + } + std::vector> args; - if (!ReadValueArgs(state, 2, argv, &args)) { + if (!ReadValueArgs(state, argv, &args)) { return nullptr; } @@ -1856,9 +1870,16 @@ Value* RangeSha1Fn(const char* name, State* state, int /* argc */, Expr* argv[]) // 1st block of each partition and check for mounting time/count. It return string "t" // if executes successfully and an empty string otherwise. -Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* CheckFirstBlockFn(const char* name, State* state, + const std::vector>& argv) { + if (argv.size() != 1) { + ErrorAbort(state, kArgsParsingFailure, "check_first_block expects 1 argument, got %zu", + argv.size()); + return StringValue(""); + } + std::vector> args; - if (!ReadValueArgs(state, 1, argv, &args)) { + if (!ReadValueArgs(state, argv, &args)) { return nullptr; } @@ -1904,9 +1925,16 @@ Value* CheckFirstBlockFn(const char* name, State* state, int argc, Expr* argv[]) } -Value* BlockImageRecoverFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* BlockImageRecoverFn(const char* name, State* state, + const std::vector>& argv) { + if (argv.size() != 2) { + ErrorAbort(state, kArgsParsingFailure, "block_image_recover expects 2 arguments, got %zu", + argv.size()); + return StringValue(""); + } + std::vector> args; - if (!ReadValueArgs(state, 2, argv, &args)) { + if (!ReadValueArgs(state, argv, &args)) { return nullptr; } diff --git a/updater/install.cpp b/updater/install.cpp index 0963333fc..c9a0270ec 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -126,15 +126,16 @@ static bool make_parents(const std::string& name) { // mount(fs_type, partition_type, location, mount_point) // mount(fs_type, partition_type, location, mount_point, mount_options) -// + // fs_type="ext4" partition_type="EMMC" location=device -Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 4 && argc != 5) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %d", name, argc); +Value* MountFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 4 && argv.size() != 5) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 4-5 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& fs_type = args[0]; @@ -143,7 +144,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { const std::string& mount_point = args[3]; std::string mount_options; - if (argc == 5) { + if (argv.size() == 5) { mount_options = args[4]; } @@ -188,15 +189,14 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(mount_point); } - // is_mounted(mount_point) -Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); +Value* IsMountedFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& mount_point = args[0]; @@ -214,12 +214,12 @@ Value* IsMountedFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(mount_point); } -Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); +Value* UnmountFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& mount_point = args[0]; @@ -265,13 +265,14 @@ static int exec_cmd(const char* path, char* const argv[]) { // 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[]) { - if (argc != 5) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %d", name, argc); +Value* FormatFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 5) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 5 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& fs_type = args[0]; @@ -332,13 +333,15 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { return nullptr; } -Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* ShowProgressFn(const char* name, State* state, + const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& frac_str = args[0]; @@ -361,13 +364,13 @@ Value* ShowProgressFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(frac_str); } -Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); +Value* SetProgressFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& frac_str = args[0]; @@ -390,13 +393,15 @@ Value* SetProgressFn(const char* name, State* state, int argc, Expr* argv[]) { // Example: package_extract_dir("system", "/system") // // Note: package_dir needs to be a relative path; dest_dir needs to be an absolute path. -Value* PackageExtractDirFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* PackageExtractDirFn(const char* name, State* state, + const std::vector>&argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& zip_path = args[0]; @@ -416,17 +421,20 @@ Value* PackageExtractDirFn(const char* name, State* state, int argc, Expr* argv[ // Extracts a single package_file from the update package and writes it to dest_file, // overwriting existing files if necessary. Without the dest_file argument, returns the // contents of the package file as a binary blob. -Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1 || argc > 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %d", name, argc); +Value* PackageExtractFileFn(const char* name, State* state, + const std::vector>& argv) { + if (argv.size() < 1 || argv.size() > 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 or 2 args, got %zu", name, + argv.size()); } - if (argc == 2) { + if (argv.size() == 2) { // The two-argument version extracts to a file. std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc); + if (!ReadArgs(state, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %zu args", name, + argv.size()); } const std::string& zip_path = args[0]; const std::string& dest_path = args[1]; @@ -468,8 +476,9 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv // The one-argument version returns the contents of the file as the result. std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { - return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %d args", name, argc); + if (!ReadArgs(state, argv, &args)) { + return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse %zu args", name, + argv.size()); } const std::string& zip_path = args[0]; @@ -495,9 +504,9 @@ Value* PackageExtractFileFn(const char* name, State* state, int argc, Expr* argv } } -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); +Value* GetPropFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::string key; if (!Evaluate(state, argv[0], &key)) { @@ -513,13 +522,14 @@ Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { // interprets 'file' as a getprop-style file (key=value pairs, one // per line. # comment lines, blank lines, lines without '=' ignored), // and returns the value for 'key' (or "" if it isn't defined). -Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* FileGetPropFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -578,9 +588,13 @@ Value* FileGetPropFn(const char* name, State* state, int argc, Expr* argv[]) { } // apply_patch_space(bytes) -Value* ApplyPatchSpaceFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* ApplyPatchSpaceFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 args, got %zu", name, + argv.size()); + } std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& bytes_str = args[0]; @@ -606,14 +620,14 @@ Value* ApplyPatchSpaceFn(const char* name, State* state, int argc, Expr* argv[]) // state. If the process is interrupted during patching, the target file may be in an intermediate // state; a copy exists in the cache partition so restarting the update can successfully update // the file. -Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 6 || (argc % 2) == 1) { +Value* ApplyPatchFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() < 6 || (argv.size() % 2) == 1) { return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 6 args and an " - "even number, got %d", name, argc); + "even number, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, 4, argv, &args)) { + if (!ReadArgs(state, argv, &args, 0, 4)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& source_filename = args[0]; @@ -627,9 +641,9 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { name, target_size_str.c_str()); } - int patchcount = (argc-4) / 2; + int patchcount = (argv.size()-4) / 2; std::vector> arg_values; - if (!ReadValueArgs(state, argc-4, argv+4, &arg_values)) { + if (!ReadValueArgs(state, argv, &arg_values, 4, argv.size() - 4)) { return nullptr; } @@ -664,20 +678,20 @@ Value* ApplyPatchFn(const char* name, State* state, int argc, Expr* argv[]) { // specified as 40 hex digits. This function differs from sha1_check(read_file(filename), // sha1 [, ...]) in that it knows to check the cache partition copy, so apply_patch_check() will // succeed even if the file was corrupted by an interrupted apply_patch() update. -Value* ApplyPatchCheckFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %d", name, - argc); +Value* ApplyPatchCheckFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() < 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s(): expected at least 1 arg, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { + if (!ReadArgs(state, argv, &args, 0, 1)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; std::vector sha1s; - if (!ReadArgs(state, argc - 1, argv + 1, &sha1s)) { + if (!ReadArgs(state, argv, &sha1s, 1, argv.size() - 1)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } int result = applypatch_check(filename.c_str(), sha1s); @@ -687,9 +701,9 @@ Value* ApplyPatchCheckFn(const char* name, State* state, int argc, Expr* argv[]) // This is the updater side handler for ui_print() in edify script. Contents // will be sent over to the recovery side for on-screen display. -Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { +Value* UIPrintFn(const char* name, State* state, const std::vector>& argv) { std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } @@ -698,31 +712,32 @@ Value* UIPrintFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(buffer); } -Value* WipeCacheFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); +Value* WipeCacheFn(const char* name, State* state, const std::vector>& argv) { + if (!argv.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %zu", name, + argv.size()); } fprintf(static_cast(state->cookie)->cmd_pipe, "wipe_cache\n"); return StringValue("t"); } -Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1) { +Value* RunProgramFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() < 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } - char* args2[argc + 1]; - for (int i = 0; i < argc; i++) { + char* args2[argv.size() + 1]; + for (size_t i = 0; i < argv.size(); i++) { args2[i] = &args[i][0]; } - args2[argc] = nullptr; + args2[argv.size()] = nullptr; - LOG(INFO) << "about to run program [" << args2[0] << "] with " << argc << " args"; + LOG(INFO) << "about to run program [" << args2[0] << "] with " << argv.size() << " args"; pid_t child = fork(); if (child == 0) { @@ -752,13 +767,13 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { // returns the sha1 of the file if it matches any of the hex // strings passed, or "" if it does not equal any of them. // -Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc < 1) { +Value* Sha1CheckFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() < 1) { return ErrorAbort(state, kArgsParsingFailure, "%s() expects at least 1 arg", name); } std::vector> args; - if (!ReadValueArgs(state, argc, argv, &args)) { + if (!ReadValueArgs(state, argv, &args)) { return nullptr; } @@ -768,11 +783,11 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { uint8_t digest[SHA_DIGEST_LENGTH]; SHA1(reinterpret_cast(args[0]->data.c_str()), args[0]->data.size(), digest); - if (argc == 1) { + if (argv.size() == 1) { return StringValue(print_sha1(digest)); } - for (int i = 1; i < argc; ++i) { + for (size_t i = 1; i < argv.size(); ++i) { uint8_t arg_digest[SHA_DIGEST_LENGTH]; if (args[i]->type != VAL_STRING) { LOG(ERROR) << name << "(): arg " << i << " is not a string; skipping"; @@ -791,13 +806,13 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { // Read a local file and return its contents (the Value* returned // is actually a FileContents*). -Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); +Value* ReadFileFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -815,13 +830,14 @@ Value* ReadFileFn(const char* name, State* state, int argc, Expr* argv[]) { // write_value(value, filename) // Writes 'value' to 'filename'. // Example: write_value("960000", "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq") -Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* WriteValueFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); } @@ -848,13 +864,14 @@ Value* WriteValueFn(const char* name, State* state, int argc, Expr* argv[]) { // property. It can be "recovery" to boot from the recovery // partition, or "" (empty string) to boot from the regular boot // partition. -Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* RebootNowFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s(): Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -890,13 +907,14 @@ Value* RebootNowFn(const char* name, State* state, int argc, Expr* argv[]) { // ("/misc" in the fstab), which is where this value is stored. The // second argument is the string to store; it should not exceed 31 // bytes. -Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* SetStageFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -923,13 +941,13 @@ Value* SetStageFn(const char* name, State* state, int argc, Expr* argv[]) { // Return the value most recently saved with SetStageFn. The argument // is the block device for the misc partition. -Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 1) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %d", name, argc); +Value* GetStageFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 1) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 1 arg, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, 1, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -944,13 +962,14 @@ Value* GetStageFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(boot.stage); } -Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 2) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %d", name, argc); +Value* WipeBlockDeviceFn(const char* name, State* state, const std::vector>& argv) { + if (argv.size() != 2) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects 2 args, got %zu", name, + argv.size()); } std::vector args; - if (!ReadArgs(state, 2, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } const std::string& filename = args[0]; @@ -967,38 +986,39 @@ Value* WipeBlockDeviceFn(const char* name, State* state, int argc, Expr* argv[]) return StringValue((status == 0) ? "t" : ""); } -Value* EnableRebootFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc != 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %d", name, argc); +Value* EnableRebootFn(const char* name, State* state, const std::vector>& argv) { + if (!argv.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects no args, got %zu", name, + argv.size()); } UpdaterInfo* ui = static_cast(state->cookie); fprintf(ui->cmd_pipe, "enable_reboot\n"); return StringValue("t"); } -Value* Tune2FsFn(const char* name, State* state, int argc, Expr* argv[]) { - if (argc == 0) { - return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %d", name, argc); +Value* Tune2FsFn(const char* name, State* state, const std::vector>& argv) { + if (argv.empty()) { + return ErrorAbort(state, kArgsParsingFailure, "%s() expects args, got %zu", name, argv.size()); } std::vector args; - if (!ReadArgs(state, argc, argv, &args)) { + if (!ReadArgs(state, argv, &args)) { return ErrorAbort(state, kArgsParsingFailure, "%s() could not read args", name); } - char* args2[argc + 1]; + char* args2[argv.size() + 1]; // Tune2fs expects the program name as its args[0] args2[0] = const_cast(name); if (args2[0] == nullptr) { return nullptr; } - for (int i = 0; i < argc; ++i) { + for (size_t i = 0; i < argv.size(); ++i) { args2[i + 1] = &args[i][0]; } // tune2fs changes the file system parameters on an ext2 file system; it // returns 0 on success. - int result = tune2fs_main(argc + 1, args2); + int result = tune2fs_main(argv.size() + 1, args2); if (result != 0) { return ErrorAbort(state, kTune2FsFailure, "%s() returned error code %d", name, result); } diff --git a/updater/updater.cpp b/updater/updater.cpp index 22c060fcb..0693cbd98 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -130,7 +130,7 @@ int main(int argc, char** argv) { // Parse the script. - Expr* root; + std::unique_ptr root; int error_count = 0; int error = parse_string(script.c_str(), &root, &error_count); if (error != 0 || error_count > 0) { -- cgit v1.2.3 From db56eb073e595a862f620e244e23471665f63527 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 23 Mar 2017 06:34:20 -0700 Subject: updater: Fix the broken case for apply_patch_check(). It's valid to provide only 1 argument to apply_patch_check(). We shouldn't fail the argument parsing. Bug: 36541737 Test: recovery_component_test passes. Test: recovery_component_test captures the failure without the fix. Test: The previously failed update applies successfully. Change-Id: Iee4c54ed33b877fc4885945b085341ec5c64f663 --- updater/install.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index c9a0270ec..f91f3fc9f 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -691,7 +691,7 @@ Value* ApplyPatchCheckFn(const char* name, State* state, const std::vector sha1s; - if (!ReadArgs(state, argv, &sha1s, 1, argv.size() - 1)) { + if (argv.size() > 1 && !ReadArgs(state, argv, &sha1s, 1, argv.size() - 1)) { return ErrorAbort(state, kArgsParsingFailure, "%s() Failed to parse the argument(s)", name); } int result = applypatch_check(filename.c_str(), sha1s); -- cgit v1.2.3 From 17e6d3f3bcd27aedc2ff8fe796ce90dddb04a714 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Thu, 23 Mar 2017 16:56:50 +0100 Subject: Fixed scanf modifier Scanf expectation is to have same type of pointer to store parsed value and modifier in format string --- updater/updater.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index 0693cbd98..c09e267a5 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -185,7 +185,7 @@ int main(int argc, char** argv) { // Parse the error code in abort message. // Example: "E30: This package is for bullhead devices." if (!line.empty() && line[0] == 'E') { - if (sscanf(line.c_str(), "E%u: ", &state.error_code) != 1) { + if (sscanf(line.c_str(), "E%d: ", &state.error_code) != 1) { LOG(ERROR) << "Failed to parse error code: [" << line << "]"; } } -- cgit v1.2.3 From bb8bce932e288189202bd8d080db0cd88c0f6d70 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Thu, 23 Mar 2017 17:16:17 +0100 Subject: Redundant checking of STL container element As of C++ specification size_type erase( const key_type& key ); removes the element (if one exists). There is no need to perform the check twice. Change-Id: I4b057c08526abc7c2a483a60f9e166e4d8f56a74 --- updater/blockimg.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index efdfec19a..12ca151a1 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -1220,9 +1220,7 @@ static int PerformCommandFree(CommandParameters& params) { const std::string& id = params.tokens[params.cpos++]; - if (stash_map.find(id) != stash_map.end()) { - stash_map.erase(id); - } + stash_map.erase(id); if (params.createdstash || params.canwrite) { return FreeStash(params.stashbase, id); -- cgit v1.2.3 From 20791bdcd7caad0e3ad3adedf7f9f932da278d96 Mon Sep 17 00:00:00 2001 From: Mikhail Lappo Date: Thu, 23 Mar 2017 21:30:36 +0100 Subject: Removed C-style casts In c++ code would be cleaner to use c++ retinterpret cast instead of old c-style notation Change-Id: Ibeef5e0c374addf108c0a8876a6be45063d8e396 --- updater/blockimg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index efdfec19a..a8146eb50 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -356,7 +356,7 @@ static bool receive_new_data(const uint8_t* data, size_t size, void* cookie) { } static void* unzip_new_data(void* cookie) { - NewThreadInfo* nti = (NewThreadInfo*) cookie; + NewThreadInfo* nti = static_cast(cookie); ProcessZipEntryContents(nti->za, &nti->entry, receive_new_data, nti); return nullptr; } -- cgit v1.2.3 From 3356777cae9ef06490d22dda434b88923cb444aa Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 13 Mar 2017 14:57:34 -0700 Subject: updater: Drop the support for BBOTA v1 and v2. The script support for BBOTA v1 and v2 has been dropped in commit 8fad03e7712082eb880ffaaffb69eb13252ce220 (platform/build). Bug: 33694730 Test: Apply an incremental with the new updater. Test: recovery_component_test Change-Id: I038b1bf8d10f030cab8ec0aa6ee565c5a9545dfd --- updater/blockimg.cpp | 728 +++++++++++++++++++++++---------------------------- 1 file changed, 330 insertions(+), 398 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 12ca151a1..b3fe4552f 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -429,46 +429,11 @@ struct CommandParameters { uint8_t* patch_start; }; -// Do a source/target load for move/bsdiff/imgdiff in version 1. -// We expect to parse the remainder of the parameter tokens as: -// -// -// -// The source range is loaded into the provided buffer, reallocating -// it to make it larger if necessary. - -static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& src_blocks, - std::vector& buffer, int fd) { - - if (params.cpos + 1 >= params.tokens.size()) { - LOG(ERROR) << "invalid parameters"; - return -1; - } - - // - RangeSet src = parse_range(params.tokens[params.cpos++]); - - // - tgt = parse_range(params.tokens[params.cpos++]); - - allocate(src.size * BLOCKSIZE, buffer); - int rc = ReadBlocks(src, buffer, fd); - src_blocks = src.size; - - return rc; -} - // Print the hash in hex for corrupted source blocks (excluding the stashed blocks which is // handled separately). static void PrintHashForCorruptedSourceBlocks(const CommandParameters& params, const std::vector& buffer) { LOG(INFO) << "unexpected contents of source blocks in cmd:\n" << params.cmdline; - if (params.version < 3) { - // TODO handle version 1,2 - LOG(WARNING) << "version number " << params.version << " is not supported to print hashes"; - return; - } - CHECK(params.tokens[0] == "move" || params.tokens[0] == "bsdiff" || params.tokens[0] == "imgdiff"); @@ -896,49 +861,46 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& blockd } static int SaveStash(CommandParameters& params, const std::string& base, - std::vector& buffer, int fd, bool usehash) { - - // - if (params.cpos + 1 >= params.tokens.size()) { - LOG(ERROR) << "missing id and/or src range fields in stash command"; - return -1; - } - const std::string& id = params.tokens[params.cpos++]; - - size_t blocks = 0; - if (usehash && LoadStash(params, base, id, true, &blocks, buffer, false) == 0) { - // Stash file already exists and has expected contents. Do not - // read from source again, as the source may have been already - // overwritten during a previous attempt. - return 0; - } + std::vector& buffer, int fd) { + // + if (params.cpos + 1 >= params.tokens.size()) { + LOG(ERROR) << "missing id and/or src range fields in stash command"; + return -1; + } - RangeSet src = parse_range(params.tokens[params.cpos++]); + const std::string& id = params.tokens[params.cpos++]; + size_t blocks = 0; + if (LoadStash(params, base, id, true, &blocks, buffer, false) == 0) { + // Stash file already exists and has expected contents. Do not read from source again, as the + // source may have been already overwritten during a previous attempt. + return 0; + } - allocate(src.size * BLOCKSIZE, buffer); - if (ReadBlocks(src, buffer, fd) == -1) { - return -1; - } - blocks = src.size; - stash_map[id] = src; + RangeSet src = parse_range(params.tokens[params.cpos++]); - if (usehash && VerifyBlocks(id, buffer, blocks, true) != 0) { - // Source blocks have unexpected contents. If we actually need this - // data later, this is an unrecoverable error. However, the command - // that uses the data may have already completed previously, so the - // possible failure will occur during source block verification. - LOG(ERROR) << "failed to load source blocks for stash " << id; - return 0; - } + allocate(src.size * BLOCKSIZE, buffer); + if (ReadBlocks(src, buffer, fd) == -1) { + return -1; + } + blocks = src.size; + stash_map[id] = src; + + if (VerifyBlocks(id, buffer, blocks, true) != 0) { + // Source blocks have unexpected contents. If we actually need this data later, this is an + // unrecoverable error. However, the command that uses the data may have already completed + // previously, so the possible failure will occur during source block verification. + LOG(ERROR) << "failed to load source blocks for stash " << id; + return 0; + } - // In verify mode, we don't need to stash any blocks. - if (!params.canwrite && usehash) { - return 0; - } + // In verify mode, we don't need to stash any blocks. + if (!params.canwrite) { + return 0; + } - LOG(INFO) << "stashing " << blocks << " blocks to " << id; - params.stashed += blocks; - return WriteStash(base, id, blocks, buffer, false, nullptr); + LOG(INFO) << "stashing " << blocks << " blocks to " << id; + params.stashed += blocks; + return WriteStash(base, id, blocks, buffer, false, nullptr); } static int FreeStash(const std::string& base, const std::string& id) { @@ -1061,26 +1023,35 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& return 0; } -// Do a source/target load for move/bsdiff/imgdiff in version 3. -// -// Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which -// tells the function whether to expect separate source and targe block hashes, or -// if they are both the same and only one hash should be expected, and -// 'isunresumable', which receives a non-zero value if block verification fails in -// a way that the update cannot be resumed anymore. -// -// If the function is unable to load the necessary blocks or their contents don't -// match the hashes, the return value is -1 and the command should be aborted. -// -// If the return value is 1, the command has already been completed according to -// the contents of the target blocks, and should not be performed again. -// -// If the return value is 0, source blocks have expected content and the command -// can be performed. - +/** + * Do a source/target load for move/bsdiff/imgdiff in version 3. + * + * We expect to parse the remainder of the parameter tokens as one of: + * + * + * (loads data from source image only) + * + * - <[stash_id:stash_range] ...> + * (loads data from stashes only) + * + * <[stash_id:stash_range] ...> + * (loads data from both source image and stashes) + * + * Parameters are the same as for LoadSrcTgtVersion2, except for 'onehash', which tells the function + * whether to expect separate source and targe block hashes, or if they are both the same and only + * one hash should be expected, and 'isunresumable', which receives a non-zero value if block + * verification fails in a way that the update cannot be resumed anymore. + * + * If the function is unable to load the necessary blocks or their contents don't match the hashes, + * the return value is -1 and the command should be aborted. + * + * If the return value is 1, the command has already been completed according to the contents of the + * target blocks, and should not be performed again. + * + * If the return value is 0, source blocks have expected content and the command can be performed. + */ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& src_blocks, - bool onehash, bool& overlap) { - + bool onehash, bool& overlap) { if (params.cpos >= params.tokens.size()) { LOG(ERROR) << "missing source hash"; return -1; @@ -1099,8 +1070,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; } @@ -1111,7 +1082,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& } if (VerifyBlocks(tgthash, tgtbuffer, tgt.size, false) == 0) { - // Target blocks already have expected content, command should be skipped + // Target blocks already have expected content, command should be skipped. return 1; } @@ -1130,13 +1101,13 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& } params.stashed += src_blocks; - // Can be deleted when the write has completed + // Can be deleted when the write has completed. if (!stash_exists) { params.freestash = srchash; } } - // Source blocks have expected content, command can proceed + // Source blocks have expected content, command can proceed. return 0; } @@ -1148,7 +1119,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& return 0; } - // Valid source data not available, update cannot be resumed + // Valid source data not available, update cannot be resumed. LOG(ERROR) << "partition has unexpected contents"; PrintHashForCorruptedSourceBlocks(params, params.buffer); @@ -1158,57 +1129,46 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& } static int PerformCommandMove(CommandParameters& params) { - size_t blocks = 0; - bool overlap = false; - int status = 0; - RangeSet tgt; + size_t blocks = 0; + bool overlap = false; + RangeSet tgt; + int status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap); - if (params.version == 1) { - status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd); - } else if (params.version == 2) { - status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd, - params.stashbase, nullptr); - } else if (params.version >= 3) { - status = LoadSrcTgtVersion3(params, tgt, blocks, true, overlap); - } + if (status == -1) { + LOG(ERROR) << "failed to read blocks for move"; + return -1; + } - if (status == -1) { - LOG(ERROR) << "failed to read blocks for move"; - return -1; - } + if (status == 0) { + params.foundwrites = true; + } else if (params.foundwrites) { + LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; + } + if (params.canwrite) { if (status == 0) { - params.foundwrites = true; - } else if (params.foundwrites) { - LOG(WARNING) << "warning: commands executed out of order [" << params.cmdname << "]"; - } - - if (params.canwrite) { - if (status == 0) { - LOG(INFO) << " moving " << blocks << " blocks"; - - if (WriteBlocks(tgt, params.buffer, params.fd) == -1) { - return -1; - } - } else { - LOG(INFO) << "skipping " << blocks << " already moved blocks"; - } + LOG(INFO) << " moving " << blocks << " blocks"; + if (WriteBlocks(tgt, params.buffer, params.fd) == -1) { + return -1; + } + } else { + LOG(INFO) << "skipping " << blocks << " already moved blocks"; } + } - if (!params.freestash.empty()) { - FreeStash(params.stashbase, params.freestash); - params.freestash.clear(); - } + if (!params.freestash.empty()) { + FreeStash(params.stashbase, params.freestash); + params.freestash.clear(); + } - params.written += tgt.size; + params.written += tgt.size; - return 0; + return 0; } static int PerformCommandStash(CommandParameters& params) { - return SaveStash(params, params.stashbase, params.buffer, params.fd, - (params.version >= 3)); + return SaveStash(params, params.stashbase, params.buffer, params.fd); } static int PerformCommandFree(CommandParameters& params) { @@ -1337,15 +1297,7 @@ static int PerformCommandDiff(CommandParameters& params) { RangeSet tgt; size_t blocks = 0; bool overlap = false; - int status = 0; - if (params.version == 1) { - status = LoadSrcTgtVersion1(params, tgt, blocks, params.buffer, params.fd); - } else if (params.version == 2) { - status = LoadSrcTgtVersion2(params, tgt, blocks, params.buffer, params.fd, - params.stashbase, nullptr); - } else if (params.version >= 3) { - status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap); - } + int status = LoadSrcTgtVersion3(params, tgt, blocks, false, overlap); if (status == -1) { LOG(ERROR) << "failed to read blocks for diff"; @@ -1471,301 +1423,281 @@ struct Command { static Value* PerformBlockImageUpdate(const char* name, State* state, const std::vector>& argv, const Command* commands, size_t cmdcount, bool dryrun) { - CommandParameters params = {}; - params.canwrite = !dryrun; + CommandParameters params = {}; + params.canwrite = !dryrun; - LOG(INFO) << "performing " << (dryrun ? "verification" : "update"); - if (state->is_retry) { - is_retry = true; - LOG(INFO) << "This update is a retry."; - } - if (argv.size() != 4) { - ErrorAbort(state, kArgsParsingFailure, "block_image_update expects 4 arguments, got %zu", - argv.size()); - return StringValue(""); - } + LOG(INFO) << "performing " << (dryrun ? "verification" : "update"); + if (state->is_retry) { + is_retry = true; + LOG(INFO) << "This update is a retry."; + } + if (argv.size() != 4) { + ErrorAbort(state, kArgsParsingFailure, "block_image_update expects 4 arguments, got %zu", + argv.size()); + return StringValue(""); + } - std::vector> args; - if (!ReadValueArgs(state, argv, &args)) { - return nullptr; - } + std::vector> args; + if (!ReadValueArgs(state, argv, &args)) { + return nullptr; + } - const Value* blockdev_filename = args[0].get(); - const Value* transfer_list_value = args[1].get(); - const Value* new_data_fn = args[2].get(); - const Value* patch_data_fn = args[3].get(); + const Value* blockdev_filename = args[0].get(); + const Value* transfer_list_value = args[1].get(); + const Value* new_data_fn = args[2].get(); + const Value* patch_data_fn = args[3].get(); - if (blockdev_filename->type != VAL_STRING) { - ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", - name); - return StringValue(""); - } - if (transfer_list_value->type != VAL_BLOB) { - ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name); - return StringValue(""); - } - if (new_data_fn->type != VAL_STRING) { - ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name); - return StringValue(""); - } - if (patch_data_fn->type != VAL_STRING) { - ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", - name); - return StringValue(""); - } + if (blockdev_filename->type != VAL_STRING) { + ErrorAbort(state, kArgsParsingFailure, "blockdev_filename argument to %s must be string", name); + return StringValue(""); + } + if (transfer_list_value->type != VAL_BLOB) { + ErrorAbort(state, kArgsParsingFailure, "transfer_list argument to %s must be blob", name); + return StringValue(""); + } + if (new_data_fn->type != VAL_STRING) { + ErrorAbort(state, kArgsParsingFailure, "new_data_fn argument to %s must be string", name); + return StringValue(""); + } + if (patch_data_fn->type != VAL_STRING) { + ErrorAbort(state, kArgsParsingFailure, "patch_data_fn argument to %s must be string", name); + return StringValue(""); + } - UpdaterInfo* ui = static_cast(state->cookie); - if (ui == nullptr) { - return StringValue(""); - } + UpdaterInfo* ui = static_cast(state->cookie); + if (ui == nullptr) { + return StringValue(""); + } - FILE* cmd_pipe = ui->cmd_pipe; - ZipArchiveHandle za = ui->package_zip; + FILE* cmd_pipe = ui->cmd_pipe; + ZipArchiveHandle za = ui->package_zip; - if (cmd_pipe == nullptr || za == nullptr) { - return StringValue(""); - } + if (cmd_pipe == nullptr || za == nullptr) { + return StringValue(""); + } - ZipString path_data(patch_data_fn->data.c_str()); - ZipEntry patch_entry; - if (FindEntry(za, path_data, &patch_entry) != 0) { - LOG(ERROR) << name << "(): no file \"" << patch_data_fn->data << "\" in package"; - return StringValue(""); - } + ZipString path_data(patch_data_fn->data.c_str()); + ZipEntry patch_entry; + if (FindEntry(za, path_data, &patch_entry) != 0) { + LOG(ERROR) << name << "(): no file \"" << patch_data_fn->data << "\" in package"; + return StringValue(""); + } - 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) { - LOG(ERROR) << name << "(): no file \"" << new_data_fn->data << "\" in package"; - return StringValue(""); - } + 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) { + LOG(ERROR) << name << "(): no file \"" << new_data_fn->data << "\" in package"; + return StringValue(""); + } - params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR))); - if (params.fd == -1) { - PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed"; - return StringValue(""); - } + params.fd.reset(TEMP_FAILURE_RETRY(ota_open(blockdev_filename->data.c_str(), O_RDWR))); + if (params.fd == -1) { + PLOG(ERROR) << "open \"" << blockdev_filename->data << "\" failed"; + return StringValue(""); + } - if (params.canwrite) { - params.nti.za = za; - params.nti.entry = new_entry; - - pthread_mutex_init(¶ms.nti.mu, nullptr); - pthread_cond_init(¶ms.nti.cv, nullptr); - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - - int error = pthread_create(¶ms.thread, &attr, unzip_new_data, ¶ms.nti); - if (error != 0) { - PLOG(ERROR) << "pthread_create failed"; - return StringValue(""); - } - } + if (params.canwrite) { + params.nti.za = za; + params.nti.entry = new_entry; - std::vector 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(""); - } + pthread_mutex_init(¶ms.nti.mu, nullptr); + pthread_cond_init(¶ms.nti.cv, nullptr); + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - // First line in transfer list is the version number - if (!android::base::ParseInt(lines[0], ¶ms.version, 1, 4)) { - LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]"; - return StringValue(""); + int error = pthread_create(¶ms.thread, &attr, unzip_new_data, ¶ms.nti); + if (error != 0) { + PLOG(ERROR) << "pthread_create failed"; + return StringValue(""); } + } - LOG(INFO) << "blockimg version is " << params.version; + std::vector 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(""); + } - // Second line in transfer list is the total number of blocks we expect to write - size_t total_blocks; - if (!android::base::ParseUint(lines[1], &total_blocks)) { - ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str()); - return StringValue(""); - } + // First line in transfer list is the version number. + if (!android::base::ParseInt(lines[0], ¶ms.version, 3, 4)) { + LOG(ERROR) << "unexpected transfer list version [" << lines[0] << "]"; + return StringValue(""); + } - if (total_blocks == 0) { - return StringValue("t"); - } + LOG(INFO) << "blockimg version is " << params.version; - size_t start = 2; - if (params.version >= 2) { - if (lines.size() < 4) { - ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", - lines.size()); - return StringValue(""); - } - - // Third line is how many stash entries are needed simultaneously - LOG(INFO) << "maximum stash entries " << lines[2]; + // Second line in transfer list is the total number of blocks we expect to write. + size_t total_blocks; + if (!android::base::ParseUint(lines[1], &total_blocks)) { + ErrorAbort(state, kArgsParsingFailure, "unexpected block count [%s]\n", lines[1].c_str()); + return StringValue(""); + } - // Fourth line is the maximum number of blocks that will be stashed simultaneously - size_t stash_max_blocks; - if (!android::base::ParseUint(lines[3], &stash_max_blocks)) { - ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n", - lines[3].c_str()); - return StringValue(""); - } + if (total_blocks == 0) { + return StringValue("t"); + } - int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase); - if (res == -1) { - return StringValue(""); - } + size_t start = 2; + if (lines.size() < 4) { + ErrorAbort(state, kArgsParsingFailure, "too few lines in the transfer list [%zu]\n", + lines.size()); + return StringValue(""); + } - params.createdstash = res; + // Third line is how many stash entries are needed simultaneously. + LOG(INFO) << "maximum stash entries " << lines[2]; - start += 2; - } + // Fourth line is the maximum number of blocks that will be stashed simultaneously + size_t stash_max_blocks; + if (!android::base::ParseUint(lines[3], &stash_max_blocks)) { + ErrorAbort(state, kArgsParsingFailure, "unexpected maximum stash blocks [%s]\n", + lines[3].c_str()); + return StringValue(""); + } - // Build a map of the available commands - std::unordered_map cmd_map; - for (size_t i = 0; i < cmdcount; ++i) { - if (cmd_map.find(commands[i].name) != cmd_map.end()) { - LOG(ERROR) << "Error: command [" << commands[i].name - << "] already exists in the cmd map."; - return StringValue(strdup("")); - } - cmd_map[commands[i].name] = &commands[i]; - } + int res = CreateStash(state, stash_max_blocks, blockdev_filename->data, params.stashbase); + if (res == -1) { + return StringValue(""); + } - int rc = -1; + params.createdstash = res; - // Subsequent lines are all individual transfer commands - for (auto it = lines.cbegin() + start; it != lines.cend(); it++) { - const std::string& line(*it); - if (line.empty()) continue; + start += 2; - params.tokens = android::base::Split(line, " "); - params.cpos = 0; - params.cmdname = params.tokens[params.cpos++].c_str(); - params.cmdline = line.c_str(); + // Build a map of the available commands + std::unordered_map cmd_map; + for (size_t i = 0; i < cmdcount; ++i) { + if (cmd_map.find(commands[i].name) != cmd_map.end()) { + LOG(ERROR) << "Error: command [" << commands[i].name << "] already exists in the cmd map."; + return StringValue(strdup("")); + } + cmd_map[commands[i].name] = &commands[i]; + } - if (cmd_map.find(params.cmdname) == cmd_map.end()) { - LOG(ERROR) << "unexpected command [" << params.cmdname << "]"; - goto pbiudone; - } + int rc = -1; - const Command* cmd = cmd_map[params.cmdname]; + // Subsequent lines are all individual transfer commands + for (auto it = lines.cbegin() + start; it != lines.cend(); it++) { + const std::string& line(*it); + if (line.empty()) continue; - if (cmd->f != nullptr && cmd->f(params) == -1) { - LOG(ERROR) << "failed to execute command [" << line << "]"; - goto pbiudone; - } + params.tokens = android::base::Split(line, " "); + params.cpos = 0; + params.cmdname = params.tokens[params.cpos++].c_str(); + params.cmdline = line.c_str(); - if (params.canwrite) { - if (ota_fsync(params.fd) == -1) { - failure_type = kFsyncFailure; - PLOG(ERROR) << "fsync failed"; - goto pbiudone; - } - fprintf(cmd_pipe, "set_progress %.4f\n", - static_cast(params.written) / total_blocks); - fflush(cmd_pipe); - } + if (cmd_map.find(params.cmdname) == cmd_map.end()) { + LOG(ERROR) << "unexpected command [" << params.cmdname << "]"; + goto pbiudone; } - if (params.canwrite) { - pthread_join(params.thread, nullptr); - - LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks; - LOG(INFO) << "stashed " << params.stashed << " blocks"; - LOG(INFO) << "max alloc needed was " << params.buffer.size(); - - 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); - fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, - params.stashed * BLOCKSIZE); - fflush(cmd_pipe); - } - // Delete stash only after successfully completing the update, as it - // may contain blocks needed to complete the update later. - DeleteStash(params.stashbase); - } else { - LOG(INFO) << "verified partition contents; update may be resumed"; - } + const Command* cmd = cmd_map[params.cmdname]; - rc = 0; + if (cmd->f != nullptr && cmd->f(params) == -1) { + LOG(ERROR) << "failed to execute command [" << line << "]"; + goto pbiudone; + } -pbiudone: - if (ota_fsync(params.fd) == -1) { + if (params.canwrite) { + if (ota_fsync(params.fd) == -1) { failure_type = kFsyncFailure; PLOG(ERROR) << "fsync failed"; + goto pbiudone; + } + fprintf(cmd_pipe, "set_progress %.4f\n", static_cast(params.written) / total_blocks); + fflush(cmd_pipe); } - // 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. - if (params.isunresumable || (!params.canwrite && params.createdstash)) { - DeleteStash(params.stashbase); - } + if (params.canwrite) { + pthread_join(params.thread, nullptr); - if (failure_type != kNoCause && state->cause_code == kNoCause) { - state->cause_code = failure_type; + LOG(INFO) << "wrote " << params.written << " blocks; expected " << total_blocks; + LOG(INFO) << "stashed " << params.stashed << " blocks"; + LOG(INFO) << "max alloc needed was " << params.buffer.size(); + + 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); + fprintf(cmd_pipe, "log bytes_stashed_%s: %zu\n", partition + 1, params.stashed * BLOCKSIZE); + fflush(cmd_pipe); } + // Delete stash only after successfully completing the update, as it may contain blocks needed + // to complete the update later. + DeleteStash(params.stashbase); + } else { + LOG(INFO) << "verified partition contents; update may be resumed"; + } - return StringValue(rc == 0 ? "t" : ""); -} + rc = 0; -// The transfer list is a text file containing commands to -// transfer data from one place to another on the target -// partition. We parse it and execute the commands in order: -// -// zero [rangeset] -// - fill the indicated blocks with zeros -// -// new [rangeset] -// - fill the blocks with data read from the new_data file -// -// erase [rangeset] -// - mark the given blocks as empty -// -// move <...> -// bsdiff <...> -// imgdiff <...> -// - read the source blocks, apply a patch (or not in the -// case of move), write result to target blocks. bsdiff or -// imgdiff specifies the type of patch; move means no patch -// at all. -// -// The format of <...> differs between versions 1 and 2; -// see the LoadSrcTgtVersion{1,2}() functions for a -// description of what's expected. -// -// stash -// - (version 2+ only) load the given source range and stash -// the data in the given slot of the stash table. -// -// free -// - (version 3+ only) free the given stash data. -// -// The creator of the transfer list will guarantee that no block -// is read (ie, used as the source for a patch or move) after it -// has been written. -// -// In version 2, the creator will guarantee that a given stash is -// loaded (with a stash command) before it's used in a -// move/bsdiff/imgdiff command. -// -// Within one command the source and target ranges may overlap so -// in general we need to read the entire source into memory before -// writing anything to the target blocks. -// -// All the patch data is concatenated into one patch_data file in -// the update package. It must be stored uncompressed because we -// memory-map it in directly from the archive. (Since patches are -// already compressed, we lose very little by not compressing -// their concatenation.) -// -// In version 3, commands that read data from the partition (i.e. -// move/bsdiff/imgdiff/stash) have one or more additional hashes -// before the range parameters, which are used to check if the -// command has already been completed and verify the integrity of -// the source data. +pbiudone: + if (ota_fsync(params.fd) == -1) { + failure_type = kFsyncFailure; + PLOG(ERROR) << "fsync failed"; + } + // 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. + if (params.isunresumable || (!params.canwrite && params.createdstash)) { + DeleteStash(params.stashbase); + } + + if (failure_type != kNoCause && state->cause_code == kNoCause) { + state->cause_code = failure_type; + } + + return StringValue(rc == 0 ? "t" : ""); +} +/** + * The transfer list is a text file containing commands to transfer data from one place to another + * on the target partition. We parse it and execute the commands in order: + * + * zero [rangeset] + * - Fill the indicated blocks with zeros. + * + * new [rangeset] + * - Fill the blocks with data read from the new_data file. + * + * erase [rangeset] + * - Mark the given blocks as empty. + * + * move <...> + * bsdiff <...> + * imgdiff <...> + * - Read the source blocks, apply a patch (or not in the case of move), write result to target + * blocks. bsdiff or imgdiff specifies the type of patch; move means no patch at all. + * + * See the comments in LoadSrcTgtVersion3() for a description of the <...> format. + * + * stash + * - Load the given source range and stash the data in the given slot of the stash table. + * + * free + * - Free the given stash data. + * + * The creator of the transfer list will guarantee that no block is read (ie, used as the source for + * a patch or move) after it has been written. + * + * The creator will guarantee that a given stash is loaded (with a stash command) before it's used + * in a move/bsdiff/imgdiff command. + * + * Within one command the source and target ranges may overlap so in general we need to read the + * entire source into memory before writing anything to the target blocks. + * + * All the patch data is concatenated into one patch_data file in the update package. It must be + * stored uncompressed because we memory-map it in directly from the archive. (Since patches are + * already compressed, we lose very little by not compressing their concatenation.) + * + * Commands that read data from the partition (i.e. move/bsdiff/imgdiff/stash) have one or more + * additional hashes before the range parameters, which are used to check if the command has already + * been completed and verify the integrity of the source data. + */ Value* BlockImageVerifyFn(const char* name, State* state, const std::vector>& argv) { // Commands which are not tested are set to nullptr to skip them completely -- cgit v1.2.3 From bcf464988e3c39fb6497bf622a14f7aea9c4feb6 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 23 Mar 2017 15:28:20 -0700 Subject: updater: Remove some redundant arguments. Clean up a few functions that take CommandParameters& as the first parameter. We don't need to take duplicate arguments if they always come from CommandParameters. This redundancy came from the point we replaced strtok()s (commit baad2d454dc07ce916442987a2908a93fe6ae298). Test: Apply an incremental update with the new updater. Change-Id: I2912b8ce6bc7580bf7f566e125f12270e679e155 --- updater/blockimg.cpp | 143 +++++++++++++++++++++++---------------------------- 1 file changed, 65 insertions(+), 78 deletions(-) (limited to 'updater') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index b3fe4552f..60ea7cb4c 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -616,8 +616,8 @@ static void DeleteStash(const std::string& base) { } } -static int LoadStash(CommandParameters& params, const std::string& base, const std::string& id, - bool verify, size_t* blocks, std::vector& buffer, bool printnoent) { +static int LoadStash(CommandParameters& params, const std::string& id, bool verify, size_t* blocks, + std::vector& buffer, bool printnoent) { // In verify mode, if source range_set was saved for the given hash, // check contents in the source blocks first. If the check fails, // search for the stashed files on /cache as usual. @@ -639,17 +639,13 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s } } - if (base.empty()) { - return -1; - } - size_t blockcount = 0; if (!blocks) { blocks = &blockcount; } - std::string fn = GetStashFileName(base, id, ""); + std::string fn = GetStashFileName(params.stashbase, id, ""); struct stat sb; int res = stat(fn.c_str(), &sb); @@ -700,7 +696,7 @@ static int LoadStash(CommandParameters& params, const std::string& base, const s } static int WriteStash(const std::string& base, const std::string& id, int blocks, - std::vector& buffer, bool checkspace, bool *exists) { + std::vector& buffer, bool checkspace, bool *exists) { if (base.empty()) { return -1; } @@ -860,49 +856,6 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& blockd return 0; // Using existing directory } -static int SaveStash(CommandParameters& params, const std::string& base, - std::vector& buffer, int fd) { - // - if (params.cpos + 1 >= params.tokens.size()) { - LOG(ERROR) << "missing id and/or src range fields in stash command"; - return -1; - } - - const std::string& id = params.tokens[params.cpos++]; - size_t blocks = 0; - if (LoadStash(params, base, id, true, &blocks, buffer, false) == 0) { - // Stash file already exists and has expected contents. Do not read from source again, as the - // source may have been already overwritten during a previous attempt. - return 0; - } - - RangeSet src = parse_range(params.tokens[params.cpos++]); - - allocate(src.size * BLOCKSIZE, buffer); - if (ReadBlocks(src, buffer, fd) == -1) { - return -1; - } - blocks = src.size; - stash_map[id] = src; - - if (VerifyBlocks(id, buffer, blocks, true) != 0) { - // Source blocks have unexpected contents. If we actually need this data later, this is an - // unrecoverable error. However, the command that uses the data may have already completed - // previously, so the possible failure will occur during source block verification. - LOG(ERROR) << "failed to load source blocks for stash " << id; - return 0; - } - - // In verify mode, we don't need to stash any blocks. - if (!params.canwrite) { - return 0; - } - - LOG(INFO) << "stashing " << blocks << " blocks to " << id; - params.stashed += blocks; - return WriteStash(base, id, blocks, buffer, false, nullptr); -} - static int FreeStash(const std::string& base, const std::string& id) { if (base.empty() || id.empty()) { return -1; @@ -942,13 +895,12 @@ static void MoveRange(std::vector& dest, const RangeSet& locs, // <[stash_id:stash_range] ...> // (loads data from both source image and stashes) // -// On return, buffer is filled with the loaded source data (rearranged -// and combined with stashed data as necessary). buffer may be -// reallocated if needed to accommodate the source data. *tgt is the -// target RangeSet. Any stashes required are loaded using LoadStash. +// On return, params.buffer is filled with the loaded source data (rearranged and combined with +// stashed data as necessary). buffer may be reallocated if needed to accommodate the source data. +// *tgt is the target RangeSet. Any stashes required are loaded using LoadStash. static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& src_blocks, - std::vector& buffer, int fd, const std::string& stashbase, bool* overlap) { + bool* overlap) { // At least it needs to provide three parameters: , // and "-"/. @@ -967,7 +919,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& return -1; } - allocate(src_blocks * BLOCKSIZE, buffer); + allocate(src_blocks * BLOCKSIZE, params.buffer); // "-" or [] if (params.tokens[params.cpos] == "-") { @@ -975,7 +927,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& params.cpos++; } else { RangeSet src = parse_range(params.tokens[params.cpos++]); - int res = ReadBlocks(src, buffer, fd); + int res = ReadBlocks(src, params.buffer, params.fd); if (overlap) { *overlap = range_overlaps(src, tgt); @@ -991,7 +943,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } RangeSet locs = parse_range(params.tokens[params.cpos++]); - MoveRange(buffer, locs, buffer); + MoveRange(params.buffer, locs, params.buffer); } // <[stash_id:stash_range]> @@ -1006,7 +958,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } std::vector stash; - int res = LoadStash(params, stashbase, tokens[0], false, nullptr, stash, true); + int res = LoadStash(params, tokens[0], false, nullptr, stash, true); if (res == -1) { // These source blocks will fail verification if used later, but we @@ -1017,7 +969,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& RangeSet locs = parse_range(tokens[1]); - MoveRange(buffer, locs, stash); + MoveRange(params.buffer, locs, stash); } return 0; @@ -1070,8 +1022,7 @@ 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, &overlap) == -1) { return -1; } @@ -1111,8 +1062,7 @@ static int LoadSrcTgtVersion3(CommandParameters& params, RangeSet& tgt, size_t& return 0; } - if (overlap && LoadStash(params, params.stashbase, srchash, true, nullptr, params.buffer, - true) == 0) { + if (overlap && LoadStash(params, srchash, true, nullptr, params.buffer, true) == 0) { // Overlapping source blocks were previously stashed, command can proceed. // We are recovering from an interrupted command, so we don't know if the // stash can safely be deleted after this command. @@ -1168,25 +1118,62 @@ static int PerformCommandMove(CommandParameters& params) { } static int PerformCommandStash(CommandParameters& params) { - return SaveStash(params, params.stashbase, params.buffer, params.fd); -} + // + if (params.cpos + 1 >= params.tokens.size()) { + LOG(ERROR) << "missing id and/or src range fields in stash command"; + return -1; + } -static int PerformCommandFree(CommandParameters& params) { - // - if (params.cpos >= params.tokens.size()) { - LOG(ERROR) << "missing stash id in free command"; - return -1; - } + const std::string& id = params.tokens[params.cpos++]; + size_t blocks = 0; + if (LoadStash(params, id, true, &blocks, params.buffer, false) == 0) { + // Stash file already exists and has expected contents. Do not read from source again, as the + // source may have been already overwritten during a previous attempt. + return 0; + } - const std::string& id = params.tokens[params.cpos++]; + RangeSet src = parse_range(params.tokens[params.cpos++]); - stash_map.erase(id); + allocate(src.size * BLOCKSIZE, params.buffer); + if (ReadBlocks(src, params.buffer, params.fd) == -1) { + return -1; + } + blocks = src.size; + stash_map[id] = src; - if (params.createdstash || params.canwrite) { - return FreeStash(params.stashbase, id); - } + if (VerifyBlocks(id, params.buffer, blocks, true) != 0) { + // Source blocks have unexpected contents. If we actually need this data later, this is an + // unrecoverable error. However, the command that uses the data may have already completed + // previously, so the possible failure will occur during source block verification. + LOG(ERROR) << "failed to load source blocks for stash " << id; + return 0; + } + // In verify mode, we don't need to stash any blocks. + if (!params.canwrite) { return 0; + } + + LOG(INFO) << "stashing " << blocks << " blocks to " << id; + params.stashed += blocks; + return WriteStash(params.stashbase, id, blocks, params.buffer, false, nullptr); +} + +static int PerformCommandFree(CommandParameters& params) { + // + if (params.cpos >= params.tokens.size()) { + LOG(ERROR) << "missing stash id in free command"; + return -1; + } + + const std::string& id = params.tokens[params.cpos++]; + stash_map.erase(id); + + if (params.createdstash || params.canwrite) { + return FreeStash(params.stashbase, id); + } + + return 0; } static int PerformCommandZero(CommandParameters& params) { -- cgit v1.2.3 From ed9db0fd73f0368be354a65d7bdc3de5d01bdc88 Mon Sep 17 00:00:00 2001 From: Dmitri Plotnikov Date: Tue, 18 Apr 2017 08:28:26 -0700 Subject: Adding support for quiescent reboot to recovery Bug: 37401320 Test: build and push OTA and hit adb reboot recovery,quiescent. The screen should remain off throughout the upgrade process. (cherry picked from commit 8706a98aa635236a95795f0a0c122bb3e591a50d) Change-Id: I79789a151f6faafda8ecc6198c2182cc2a91da70 --- updater/install.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'updater') diff --git a/updater/install.cpp b/updater/install.cpp index f91f3fc9f..84cf5d6c0 100644 --- a/updater/install.cpp +++ b/updater/install.cpp @@ -890,7 +890,10 @@ Value* RebootNowFn(const char* name, State* state, const std::vector Date: Wed, 14 Jun 2017 15:30:39 -0700 Subject: Fix "No file_contexts" warning Fixed by Loading the file_contexts specified in libselinux, whereas previously recovery loaded /file_contexts which no longer exists. Bug: 62587423 Test: build and flash recovery on Angler. Warning is gone. Test: Wipe data and cache. Test: sideload OTA Change-Id: I11581c878b860ac5f412e6e8e7acde811f37870f (cherry picked from commit 2330dd8733ce0b207058e3003a3b1efebc022394) --- updater/updater.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'updater') diff --git a/updater/updater.cpp b/updater/updater.cpp index c09e267a5..f3e282044 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -139,9 +140,8 @@ int main(int argc, char** argv) { return 6; } - struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "/file_contexts" } }; - - sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); + sehandle = selinux_android_file_context_handle(); + selinux_android_set_sehandle(sehandle); if (!sehandle) { fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); -- cgit v1.2.3