From 8ff84d7cfb1d51221f61ad6ebd97434b6f8b658a Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 19 Dec 2018 16:21:55 -0800 Subject: updater: add functions to modify dynamic partition metadata Test: sideload full OTA on cuttlefish Test: sideload incremental OTA on cuttlefish (that grows system, shrinks vendor, and move vendor to group foo) Test: verify that /cache/recovery/cc46ebfd04058569d0c6c1431c6af6c1328458e4 exists (sha1sum of "system") Bug: 111801737 Change-Id: Ibdf6565bc1b60f3665c01739b4c95a85f0261ae5 --- updater/blockimg.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 9 deletions(-) (limited to 'updater/blockimg.cpp') diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index e35d48368..6e5d5bb55 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -70,6 +70,7 @@ static constexpr size_t BLOCKSIZE = 4096; static constexpr mode_t STASH_DIRECTORY_MODE = 0700; static constexpr mode_t STASH_FILE_MODE = 0600; +static constexpr mode_t MARKER_DIRECTORY_MODE = 0700; static CauseCode failure_type = kNoCause; static bool is_retry = false; @@ -167,15 +168,22 @@ static bool UpdateLastCommandIndex(size_t command_index, const std::string& comm return true; } -static bool SetPartitionUpdatedMarker(const std::string& marker) { +bool SetUpdatedMarker(const std::string& marker) { + auto dirname = android::base::Dirname(marker); + auto res = mkdir(dirname.c_str(), MARKER_DIRECTORY_MODE); + if (res == -1 && errno != EEXIST) { + PLOG(ERROR) << "Failed to create directory for marker: " << dirname; + return false; + } + if (!android::base::WriteStringToFile("", marker)) { PLOG(ERROR) << "Failed to write to marker file " << marker; return false; } - if (!FsyncDir(android::base::Dirname(marker))) { + if (!FsyncDir(dirname)) { return false; } - LOG(INFO) << "Wrote partition updated marker to " << marker; + LOG(INFO) << "Wrote updated marker to " << marker; return true; } @@ -1573,6 +1581,43 @@ using CommandFunction = std::function; using CommandMap = std::unordered_map; +static bool Sha1DevicePath(const std::string& path, uint8_t digest[SHA_DIGEST_LENGTH]) { + auto device_name = android::base::Basename(path); + auto dm_target_name_path = "/sys/block/" + device_name + "/dm/name"; + + struct stat sb; + if (stat(dm_target_name_path.c_str(), &sb) == 0) { + // This is a device mapper target. Use partition name as part of the hash instead. Do not + // include extents as part of the hash, because the size of a partition may be shrunk after + // the patches are applied. + std::string dm_target_name; + if (!android::base::ReadFileToString(dm_target_name_path, &dm_target_name)) { + PLOG(ERROR) << "Cannot read " << dm_target_name_path; + return false; + } + SHA1(reinterpret_cast(dm_target_name.data()), dm_target_name.size(), digest); + return true; + } + + if (errno != ENOENT) { + // This is a device mapper target, but its name cannot be retrieved. + PLOG(ERROR) << "Cannot get dm target name for " << path; + return false; + } + + // This doesn't appear to be a device mapper target, but if its name starts with dm-, something + // else might have gone wrong. + if (android::base::StartsWith(device_name, "dm-")) { + LOG(WARNING) << "Device " << path << " starts with dm- but is not mapped by device-mapper."; + } + + // 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. + SHA1(reinterpret_cast(path.data()), path.size(), digest); + return true; +} + static Value* PerformBlockImageUpdate(const char* name, State* state, const std::vector>& argv, const CommandMap& command_map, bool dryrun) { @@ -1657,12 +1702,10 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, return StringValue(""); } - // 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_filename->data.data()), - blockdev_filename->data.size(), digest); + if (!Sha1DevicePath(blockdev_filename->data, digest)) { + return StringValue(""); + } params.stashbase = print_sha1(digest); // Possibly do return early on retry, by checking the marker. If the update on this partition has @@ -1884,7 +1927,7 @@ pbiudone: // Create a marker on /cache partition, which allows skipping the update on this partition on // retry. The marker will be removed once booting into normal boot, or before starting next // fresh install. - if (!SetPartitionUpdatedMarker(updated_marker)) { + if (!SetUpdatedMarker(updated_marker)) { LOG(WARNING) << "Failed to set updated marker; continuing"; } } -- cgit v1.2.3