diff options
Diffstat (limited to 'updater/blockimg.cpp')
-rw-r--r-- | updater/blockimg.cpp | 308 |
1 files changed, 149 insertions, 159 deletions
diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 7257e2399..6755d78cb 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -41,106 +41,104 @@ #include <android-base/parseint.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> +#include <applypatch/applypatch.h> +#include <openssl/sha.h> #include <ziparchive/zip_archive.h> -#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. - size_t size; - std::vector<size_t> pos; // Actual limit is INT_MAX. + size_t count; // Limit is INT_MAX. + size_t size; + std::vector<size_t> pos; // Actual limit is INT_MAX. }; static CauseCode failure_type = kNoCause; static bool is_retry = false; static std::unordered_map<std::string, RangeSet> 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<std::string> pieces = android::base::Split(range_text, ","); - if (pieces.size() < 3) { - goto err; - } + std::vector<std::string> 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<size_t>(INT_MAX))) { - goto err; - } + size_t num; + if (!android::base::ParseUint(pieces[0], &num, static_cast<size_t>(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; + 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<size_t>(INT_MAX))) { - goto err; - } - - if (!android::base::ParseUint(pieces[i+2].c_str(), &rs.pos[i+1], - static_cast<size_t>(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<size_t>(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<size_t>(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 +429,10 @@ static int LoadSrcTgtVersion1(CommandParameters& params, RangeSet& tgt, size_t& } // <src_range> - RangeSet src; - parse_range(params.tokens[params.cpos++], src); + RangeSet src = parse_range(params.tokens[params.cpos++]); // <tgt_range> - 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); @@ -509,18 +506,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<int*>(data); - *size += sb.st_size; + size_t* size = static_cast<size_t*>(data); + *size += sb.st_size; } // Deletes the stash directory and all files in it. Assumes that it only @@ -710,63 +707,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<const uint8_t*>(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<const uint8_t*>(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, @@ -787,8 +788,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 +872,7 @@ static int LoadSrcTgtVersion2(CommandParameters& params, RangeSet& tgt, size_t& } // <tgt_range> - parse_range(params.tokens[params.cpos++], tgt); + tgt = parse_range(params.tokens[params.cpos++]); // <src_block_count> const std::string& token = params.tokens[params.cpos++]; @@ -888,8 +888,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 +904,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 +929,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 +1113,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 +1156,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 +1311,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"; @@ -1358,7 +1352,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."; @@ -1393,8 +1387,7 @@ static Value* PerformBlockImageUpdate(const char* name, State* state, int /* arg return StringValue(""); } - UpdaterInfo* ui = reinterpret_cast<UpdaterInfo*>(state->cookie); - + UpdaterInfo* ui = static_cast<UpdaterInfo*>(state->cookie); if (ui == nullptr) { return StringValue(""); } @@ -1452,7 +1445,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 +1453,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 +1466,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 +1507,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 +1523,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 +1533,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<double>(params.written) / total_blocks); fflush(cmd_pipe); } } @@ -1555,7 +1547,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, @@ -1707,8 +1699,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 +1823,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]; |