From d34e6bc44b0e58a3261cd7070a1525099932f205 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 13 Jul 2018 13:11:09 -0700 Subject: applypatch: Change applypatch command-line arguments. This applies to the standalone applypatch executable (/system/bin/applypatch on device). This executable is only used when installing (via patching or flashing) a recovery image on non-A/B device. This CL removes the support for patching non-eMMC targets from applypatch that has been deprecated as part of file-based OTA. For patching eMMC targets, it also drops the support for accepting multiple patches (not useful, since the source file must be fixed). This CL needs the matching change in the same topic, which writes the script of "/system/bin/install-recovery.sh". Note that this CL doesn't chanage the applypatch API signatures, in order to minimize the CL size. *BEFORE* usage: /system/bin/applypatch [-b ] [: ...] or /system/bin/applypatch -c [ ...] or /system/bin/applypatch -l Filenames may be of the form EMMC::::::... to specify reading from or writing to an EMMC partition. *AFTER* Usage: check mode applypatch --check EMMC::: flash mode applypatch --flash --target EMMC::: patch mode applypatch [--bonus ] --patch --target EMMC::: --source EMMC::: show license applypatch --license Bug: 110106408 Test: Run recovery_component_test and recovery_unit_test on marlin. Test: Build a non-A/B target that has /system/bin/install-recovery.sh. Verify that it installs recovery image successfully. Test: Build a non-A/B target that has /system/bin/install-recovery.sh in flashing mode. Verify that it installs recovery image successfully. Change-Id: I71f9a71fb457e6f663e0b5511946949e65b4b78c --- applypatch/applypatch_modes.cpp | 261 +++++++++++++++++++++------------------- 1 file changed, 134 insertions(+), 127 deletions(-) (limited to 'applypatch/applypatch_modes.cpp') diff --git a/applypatch/applypatch_modes.cpp b/applypatch/applypatch_modes.cpp index ec95325fc..f130ea222 100644 --- a/applypatch/applypatch_modes.cpp +++ b/applypatch/applypatch_modes.cpp @@ -16,6 +16,7 @@ #include "applypatch_modes.h" +#include #include #include #include @@ -25,6 +26,7 @@ #include #include +#include #include #include #include @@ -33,157 +35,162 @@ #include "applypatch/applypatch.h" #include "edify/expr.h" -static int CheckMode(int argc, const char** argv) { - if (argc < 3) { - return 2; - } - std::vector sha1; - for (int i = 3; i < argc; i++) { - sha1.push_back(argv[i]); - } - - return applypatch_check(argv[2], sha1); -} - -// Parse arguments (which should be of the form ":" into the -// new parallel arrays *sha1s and *files. Returns true on success. -static bool ParsePatchArgs(int argc, const char** argv, std::vector* sha1s, - std::vector* files) { - if (sha1s == nullptr) { - return false; - } - for (int i = 0; i < argc; ++i) { - std::vector pieces = android::base::Split(argv[i], ":"); - if (pieces.size() != 2) { - LOG(ERROR) << "Failed to parse patch argument \"" << argv[i] << "\""; - return false; - } - - uint8_t digest[SHA_DIGEST_LENGTH]; - if (ParseSha1(pieces[0], digest) != 0) { - LOG(ERROR) << "Failed to parse SHA-1 \"" << argv[i] << "\""; - return false; - } - - sha1s->push_back(pieces[0]); - FileContents fc; - if (LoadFileContents(pieces[1].c_str(), &fc) != 0) { - return false; - } - files->push_back(std::move(fc)); - } - return true; -} - -static int FlashMode(const char* src_filename, const char* tgt_filename, - const char* tgt_sha1, size_t tgt_size) { - return applypatch_flash(src_filename, tgt_filename, tgt_sha1, tgt_size); +static int CheckMode(const std::string& target) { + return applypatch_check(target, {}); } -static int PatchMode(int argc, const char** argv) { - std::unique_ptr bonus; - if (argc >= 3 && strcmp(argv[1], "-b") == 0) { - FileContents bonus_fc; - if (LoadFileContents(argv[2], &bonus_fc) != 0) { - LOG(ERROR) << "Failed to load bonus file " << argv[2]; - return 1; - } - bonus = std::make_unique(Value::Type::BLOB, - std::string(bonus_fc.data.cbegin(), bonus_fc.data.cend())); - argc -= 2; - argv += 2; +static int FlashMode(const std::string& target_emmc, const std::string& source_file) { + std::vector pieces = android::base::Split(target_emmc, ":"); + if (pieces.size() != 4 || pieces[0] != "EMMC") { + return 2; + } + size_t target_size; + if (!android::base::ParseUint(pieces[2], &target_size) || target_size == 0) { + LOG(ERROR) << "Failed to parse \"" << pieces[2] << "\" as byte count"; + return 1; } + return applypatch_flash(source_file.c_str(), target_emmc.c_str(), pieces[3].c_str(), target_size); +} - if (argc < 4) { +static int PatchMode(const std::string& target_emmc, const std::string& source_emmc, + const std::string& patch_file, const std::string& bonus_file) { + std::vector target_pieces = android::base::Split(target_emmc, ":"); + if (target_pieces.size() != 4 || target_pieces[0] != "EMMC") { return 2; } size_t target_size; - if (!android::base::ParseUint(argv[4], &target_size) || target_size == 0) { - LOG(ERROR) << "Failed to parse \"" << argv[4] << "\" as byte count"; + if (!android::base::ParseUint(target_pieces[2], &target_size) || target_size == 0) { + LOG(ERROR) << "Failed to parse \"" << target_pieces[2] << "\" as byte count"; return 1; } - // If no : is provided, it is in flash mode. - if (argc == 5) { - if (bonus) { - LOG(ERROR) << "bonus file not supported in flash mode"; - return 1; - } - return FlashMode(argv[1], argv[2], argv[3], target_size); + std::vector source_pieces = android::base::Split(source_emmc, ":"); + if (source_pieces.size() != 4 || source_pieces[0] != "EMMC") { + return 2; } - std::vector sha1s; - std::vector files; - if (!ParsePatchArgs(argc - 5, argv + 5, &sha1s, &files)) { - LOG(ERROR) << "Failed to parse patch args"; + size_t source_size; + if (!android::base::ParseUint(source_pieces[2], &source_size) || source_size == 0) { + LOG(ERROR) << "Failed to parse \"" << source_pieces[2] << "\" as byte count"; return 1; } + std::string contents; + if (!android::base::ReadFileToString(patch_file, &contents)) { + PLOG(ERROR) << "Failed to read patch file \"" << patch_file << "\""; + return 1; + } std::vector> patches; - for (const auto& file : files) { - patches.push_back(std::make_unique(Value::Type::BLOB, - std::string(file.data.cbegin(), file.data.cend()))); + patches.push_back(std::make_unique(Value::Type::BLOB, std::move(contents))); + std::vector sha1s{ source_pieces[3] }; + + std::unique_ptr bonus; + if (!bonus_file.empty()) { + std::string bonus_contents; + if (!android::base::ReadFileToString(bonus_file, &bonus_contents)) { + PLOG(ERROR) << "Failed to read bonus file \"" << bonus_file << "\""; + return 1; + } + bonus = std::make_unique(Value::Type::BLOB, std::move(bonus_contents)); } - return applypatch(argv[1], argv[2], argv[3], target_size, sha1s, patches, bonus.get()); + + return applypatch(source_emmc.c_str(), target_emmc.c_str(), target_pieces[3].c_str(), target_size, + sha1s, patches, bonus.get()); +} + +static void Usage() { + printf( + "Usage: \n" + "check mode\n" + " applypatch --check EMMC:::\n\n" + "flash mode\n" + " applypatch --flash \n" + " --target EMMC:::\n\n" + "patch mode\n" + " applypatch [--bonus ]\n" + " --patch \n" + " --target EMMC:::\n" + " --source EMMC:::\n\n" + "show license\n" + " applypatch --license\n" + "\n\n"); } -// This program (applypatch) applies binary patches to files in a way that -// is safe (the original file is not touched until we have the desired -// replacement for it) and idempotent (it's okay to run this program -// multiple times). -// -// - if the sha1 hash of is , does nothing and exits -// successfully. -// -// - otherwise, if no : is provided, flashes with -// . must be a partition name, while must -// be a regular image file. will not be deleted on success. -// -// - otherwise, if the sha1 hash of is , applies the -// bsdiff to to produce a new file (the type of patch -// is automatically detected from the file header). If that new -// file has sha1 hash , moves it to replace , and -// exits successfully. Note that if and are -// not the same, is NOT deleted on success. -// may be the string "-" to mean "the same as src-file". -// -// - otherwise, or if any error is encountered, exits with non-zero -// status. -// -// (or in check mode) may refer to an EMMC partition -// to read the source data. See the comments for the -// LoadPartitionContents() function for the format of such a filename. - -int applypatch_modes(int argc, const char** argv) { - if (argc < 2) { - usage: +int applypatch_modes(int argc, char* argv[]) { + static constexpr struct option OPTIONS[]{ // clang-format off - LOG(INFO) << "Usage: \n" - << " " << argv[0] << " [-b ] " - " [: ...]\n" - << " " << argv[0] << " -c [ ...]\n" - << " " << argv[0] << " -l\n" - << "\n" - << "Filenames may be of the form\n" - << " EMMC::::::...\n" - << "to specify reading from or writing to an EMMC partition.\n\n"; + { "bonus", required_argument, nullptr, 0 }, + { "check", required_argument, nullptr, 0 }, + { "flash", required_argument, nullptr, 0 }, + { "license", no_argument, nullptr, 0 }, + { "patch", required_argument, nullptr, 0 }, + { "source", required_argument, nullptr, 0 }, + { "target", required_argument, nullptr, 0 }, + { nullptr, 0, nullptr, 0 }, // clang-format on - return 2; + }; + + std::string check_target; + std::string source; + std::string target; + std::string patch; + std::string bonus; + + bool check_mode = false; + bool flash_mode = false; + bool patch_mode = false; + + optind = 1; + + int arg; + int option_index; + while ((arg = getopt_long(argc, argv, "", OPTIONS, &option_index)) != -1) { + switch (arg) { + case 0: { + std::string option = OPTIONS[option_index].name; + if (option == "bonus") { + bonus = optarg; + } else if (option == "check") { + check_target = optarg; + check_mode = true; + } else if (option == "flash") { + source = optarg; + flash_mode = true; + } else if (option == "license") { + return ShowLicenses(); + } else if (option == "patch") { + patch = optarg; + patch_mode = true; + } else if (option == "source") { + source = optarg; + } else if (option == "target") { + target = optarg; + } + break; + } + case '?': + default: + LOG(ERROR) << "Invalid argument"; + Usage(); + return 2; + } } - int result; - - if (strncmp(argv[1], "-l", 3) == 0) { - result = ShowLicenses(); - } else if (strncmp(argv[1], "-c", 3) == 0) { - result = CheckMode(argc, argv); - } else { - result = PatchMode(argc, argv); + if (check_mode) { + return CheckMode(check_target); } - - if (result == 2) { - goto usage; + if (flash_mode) { + if (!bonus.empty()) { + LOG(ERROR) << "bonus file not supported in flash mode"; + return 1; + } + return FlashMode(target, source); } - return result; + if (patch_mode) { + return PatchMode(target, source, patch, bonus); + } + + Usage(); + return 2; } -- cgit v1.2.3