summaryrefslogtreecommitdiffstats
path: root/updater/blockimg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'updater/blockimg.cpp')
-rw-r--r--updater/blockimg.cpp100
1 files changed, 74 insertions, 26 deletions
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp
index 838845673..07c3c7b52 100644
--- a/updater/blockimg.cpp
+++ b/updater/blockimg.cpp
@@ -53,6 +53,7 @@
#include <ziparchive/zip_archive.h>
#include "edify/expr.h"
+#include "otautil/dirutil.h"
#include "otautil/error_code.h"
#include "otautil/paths.h"
#include "otautil/print_sha1.h"
@@ -69,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;
@@ -109,7 +111,7 @@ static bool ParseLastCommandFile(size_t* last_command_index) {
return false;
}
- if (!android::base::ParseInt(lines[0], last_command_index)) {
+ if (!android::base::ParseUint(lines[0], last_command_index)) {
LOG(ERROR) << "Failed to parse integer in: " << lines[0];
return false;
}
@@ -166,26 +168,37 @@ 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;
}
-static bool discard_blocks(int fd, off64_t offset, uint64_t size) {
- // Don't discard blocks unless the update is a retry run.
- if (!is_retry) {
+static bool discard_blocks(int fd, off64_t offset, uint64_t size, bool force = false) {
+ // Don't discard blocks unless the update is a retry run or force == true
+ if (!is_retry && !force) {
return true;
}
uint64_t args[2] = { static_cast<uint64_t>(offset), size };
if (ioctl(fd, BLKDISCARD, &args) == -1) {
+ // On devices that does not support BLKDISCARD, ignore the error.
+ if (errno == EOPNOTSUPP) {
+ return true;
+ }
PLOG(ERROR) << "BLKDISCARD ioctl failed";
return false;
}
@@ -874,7 +887,7 @@ static int CreateStash(State* state, size_t maxblocks, const std::string& base)
size_t max_stash_size = maxblocks * BLOCKSIZE;
if (res == -1) {
LOG(INFO) << "creating stash " << dirname;
- res = mkdir(dirname.c_str(), STASH_DIRECTORY_MODE);
+ res = mkdir_recursively(dirname, STASH_DIRECTORY_MODE, false, nullptr);
if (res != 0) {
ErrorAbort(state, kStashCreationFailure, "mkdir \"%s\" failed: %s", dirname.c_str(),
@@ -1399,7 +1412,10 @@ static int PerformCommandDiff(CommandParameters& params) {
// We expect the output of the patcher to fill the tgt ranges exactly.
if (!writer.Finished()) {
- LOG(ERROR) << "range sink underrun?";
+ LOG(ERROR) << "Failed to fully write target blocks (range sink underrun): Missing "
+ << writer.AvailableSpace() << " bytes";
+ failure_type = kPatchApplicationFailure;
+ return -1;
}
} else {
LOG(INFO) << "skipping " << blocks << " blocks already patched to " << tgt.blocks() << " ["
@@ -1445,14 +1461,9 @@ static int PerformCommandErase(CommandParameters& params) {
LOG(INFO) << " erasing " << tgt.blocks() << " blocks";
for (const auto& [begin, end] : tgt) {
- uint64_t blocks[2];
- // offset in bytes
- blocks[0] = begin * static_cast<uint64_t>(BLOCKSIZE);
- // length in bytes
- blocks[1] = (end - begin) * static_cast<uint64_t>(BLOCKSIZE);
-
- if (ioctl(params.fd, BLKDISCARD, &blocks) == -1) {
- PLOG(ERROR) << "BLKDISCARD ioctl failed";
+ off64_t offset = static_cast<off64_t>(begin) * BLOCKSIZE;
+ size_t size = (end - begin) * BLOCKSIZE;
+ if (!discard_blocks(params.fd, offset, size, true /* force */)) {
return -1;
}
}
@@ -1514,7 +1525,7 @@ static int PerformCommandComputeHashTree(CommandParameters& params) {
// Starts the hash_tree computation.
HashTreeBuilder builder(BLOCKSIZE, hash_function);
- if (!builder.Initialize(source_ranges.blocks() * BLOCKSIZE, salt)) {
+ if (!builder.Initialize(static_cast<int64_t>(source_ranges.blocks()) * BLOCKSIZE, salt)) {
LOG(ERROR) << "Failed to initialize hash tree computation, source " << source_ranges.ToString()
<< ", salt " << salt_hex;
return -1;
@@ -1570,6 +1581,43 @@ using CommandFunction = std::function<int(CommandParameters&)>;
using CommandMap = std::unordered_map<Command::Type, CommandFunction>;
+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<const uint8_t*>(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<const uint8_t*>(path.data()), path.size(), digest);
+ return true;
+}
+
static Value* PerformBlockImageUpdate(const char* name, State* state,
const std::vector<std::unique_ptr<Expr>>& argv,
const CommandMap& command_map, bool dryrun) {
@@ -1654,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<const uint8_t*>(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
@@ -1869,8 +1915,10 @@ pbiudone:
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);
+ fprintf(cmd_pipe, "log bytes_written_%s: %" PRIu64 "\n", partition + 1,
+ static_cast<uint64_t>(params.written) * BLOCKSIZE);
+ fprintf(cmd_pipe, "log bytes_stashed_%s: %" PRIu64 "\n", partition + 1,
+ static_cast<uint64_t>(params.stashed) * BLOCKSIZE);
fflush(cmd_pipe);
}
// Delete stash only after successfully completing the update, as it may contain blocks needed
@@ -1881,7 +1929,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";
}
}