summaryrefslogtreecommitdiffstats
path: root/applypatch/applypatch.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'applypatch/applypatch.cpp')
-rw-r--r--applypatch/applypatch.cpp320
1 files changed, 209 insertions, 111 deletions
diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp
index 7be3fdbde..54c37eb34 100644
--- a/applypatch/applypatch.cpp
+++ b/applypatch/applypatch.cpp
@@ -37,6 +37,9 @@
#include <android-base/strings.h>
#include <openssl/sha.h>
+#include "bmlutils/bmlutils.h"
+#include "mtdutils/mtdutils.h"
+
#include "edify/expr.h"
#include "ota_io.h"
#include "print_sha1.h"
@@ -47,11 +50,16 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr
const std::string& target_filename,
const uint8_t target_sha1[SHA_DIGEST_LENGTH], const Value* bonus_data);
+static bool mtd_partitions_scanned = false;
+
// Read a file into memory; store the file contents and associated metadata in *file.
// Return 0 on success.
int LoadFileContents(const char* filename, FileContents* file) {
- // A special 'filename' beginning with "EMMC:" means to load the contents of a partition.
- if (strncmp(filename, "EMMC:", 5) == 0) {
+ // A special 'filename' beginning with "MTD:" or "EMMC:" means to
+ // load the contents of a partition.
+ if (strncmp(filename, "MTD:", 4) == 0 ||
+ strncmp(filename, "EMMC:", 5) == 0 ||
+ strncmp(filename, "BML:", 4) == 0) {
return LoadPartitionContents(filename, file);
}
@@ -91,13 +99,27 @@ int LoadFileContents(const char* filename, FileContents* file) {
// "end-of-file" marker), so the caller must specify the possible
// lengths and the hash of the data, and we'll do the load expecting
// to find one of those hashes.
+enum PartitionType { MTD, EMMC };
+
static int LoadPartitionContents(const std::string& filename, FileContents* file) {
std::vector<std::string> pieces = android::base::Split(filename, ":");
- if (pieces.size() < 4 || pieces.size() % 2 != 0 || pieces[0] != "EMMC") {
+ if (pieces.size() < 4 || pieces.size() % 2 != 0) {
printf("LoadPartitionContents called with bad filename \"%s\"\n", filename.c_str());
return -1;
}
+ enum PartitionType type;
+ if (pieces[0] == "MTD") {
+ type = MTD;
+ } else if (pieces[0] == "EMMC") {
+ type = EMMC;
+ } else if (pieces[0] == "BML") {
+ type = EMMC;
+ } else {
+ printf("LoadPartitionContents called with bad filename (%s)\n", filename.c_str());
+ return -1;
+ }
+
size_t pair_count = (pieces.size() - 2) / 2; // # of (size, sha1) pairs in filename
std::vector<std::pair<size_t, std::string>> pairs;
for (size_t i = 0; i < pair_count; ++i) {
@@ -146,6 +168,14 @@ static int LoadPartitionContents(const std::string& filename, FileContents* file
buffer_ptr += read;
}
+ if (pieces[0] == "BML") {
+ if (strcmp(partition, "boot") == 0) {
+ partition = BOARD_BML_BOOT;
+ } else if (strcmp(partition, "recovery") == 0) {
+ partition = BOARD_BML_RECOVERY;
+ }
+ }
+
// Duplicate the SHA context and finalize the duplicate so we can
// check it against this pair's expected hash.
SHA_CTX temp_ctx;
@@ -226,131 +256,199 @@ int SaveFileContents(const char* filename, const FileContents* file) {
// might contain multiple colons, but WriteToPartition() only uses the first
// two and ignores the rest. Return 0 on success.
int WriteToPartition(const unsigned char* data, size_t len, const std::string& target) {
- std::vector<std::string> pieces = android::base::Split(target, ":");
- if (pieces.size() < 2 || pieces[0] != "EMMC") {
- printf("WriteToPartition called with bad target (%s)\n", target.c_str());
- return -1;
- }
-
- const char* partition = pieces[1].c_str();
- unique_fd fd(ota_open(partition, O_RDWR));
- if (fd == -1) {
- printf("failed to open %s: %s\n", partition, strerror(errno));
- return -1;
- }
+ std::string copy(target);
+ std::vector<std::string> pieces = android::base::Split(copy, ":");
- size_t start = 0;
- bool success = false;
- for (size_t attempt = 0; attempt < 2; ++attempt) {
- if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
- printf("failed seek on %s: %s\n", partition, strerror(errno));
- return -1;
- }
- while (start < len) {
- size_t to_write = len - start;
- if (to_write > 1 << 20) to_write = 1 << 20;
-
- ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data + start, to_write));
- if (written == -1) {
- printf("failed write writing to %s: %s\n", partition, strerror(errno));
+ if (pieces.size() < 2) {
+ printf("WriteToPartition called with bad target (%s)\n", target.c_str());
return -1;
- }
- start += written;
- }
-
- if (ota_fsync(fd) != 0) {
- printf("failed to sync to %s: %s\n", partition, strerror(errno));
- return -1;
- }
- if (ota_close(fd) != 0) {
- printf("failed to close %s: %s\n", partition, strerror(errno));
- return -1;
- }
-
- fd.reset(ota_open(partition, O_RDONLY));
- if (fd == -1) {
- printf("failed to reopen %s for verify: %s\n", partition, strerror(errno));
- return -1;
}
- // Drop caches so our subsequent verification read won't just be reading the cache.
- sync();
- unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
- if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
- printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
+ enum PartitionType type;
+ if (pieces[0] == "MTD") {
+ type = MTD;
+ } else if (pieces[0] == "EMMC") {
+ type = EMMC;
+ } else if (pieces[0] == "BML") {
+ type = EMMC;
} else {
- printf(" caches dropped\n");
- }
- ota_close(dc);
- sleep(1);
-
- // Verify.
- if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
- printf("failed to seek back to beginning of %s: %s\n", partition, strerror(errno));
- return -1;
+ printf("WriteToPartition called with bad target (%s)\n", target.c_str());
+ return -1;
}
- unsigned char buffer[4096];
- start = len;
- for (size_t p = 0; p < len; p += sizeof(buffer)) {
- size_t to_read = len - p;
- if (to_read > sizeof(buffer)) {
- to_read = sizeof(buffer);
- }
+ const char* partition = pieces[1].c_str();
- size_t so_far = 0;
- while (so_far < to_read) {
- ssize_t read_count = TEMP_FAILURE_RETRY(ota_read(fd, buffer + so_far, to_read - so_far));
- if (read_count == -1) {
- printf("verify read error %s at %zu: %s\n", partition, p, strerror(errno));
- return -1;
- } else if (read_count == 0) {
- printf("verify read reached unexpected EOF, %s at %zu\n", partition, p);
- return -1;
- }
- if (static_cast<size_t>(read_count) < to_read) {
- printf("short verify read %s at %zu: %zd %zu\n", partition, p, read_count, to_read);
+ if (pieces[0] == "BML") {
+ if (strcmp(partition, "boot") == 0) {
+ partition = BOARD_BML_BOOT;
+ } else if (strcmp(partition, "recovery") == 0) {
+ partition = BOARD_BML_RECOVERY;
}
- so_far += read_count;
- }
- if (memcmp(buffer, data + p, to_read) != 0) {
- printf("verification failed starting at %zu\n", p);
- start = p;
- break;
- }
+ int bmlpartition = open(partition, O_RDWR | O_LARGEFILE);
+ if (bmlpartition < 0)
+ return -1;
+ if (ioctl(bmlpartition, BML_UNLOCK_ALL, 0)) {
+ printf("failed to unlock BML partition: (%s)\n", partition);
+ return -1;
+ }
+ close(bmlpartition);
}
- if (start == len) {
- printf("verification read succeeded (attempt %zu)\n", attempt + 1);
- success = true;
- break;
+ if (partition == NULL) {
+ printf("bad partition target name \"%s\"\n", target.c_str());
+ return -1;
}
- if (ota_close(fd) != 0) {
- printf("failed to close %s: %s\n", partition, strerror(errno));
- return -1;
- }
+ switch (type) {
+ case MTD: {
+ if (!mtd_partitions_scanned) {
+ mtd_scan_partitions();
+ mtd_partitions_scanned = true;
+ }
+
+ const MtdPartition* mtd = mtd_find_partition_by_name(partition);
+ if (mtd == NULL) {
+ printf("mtd partition \"%s\" not found for writing\n", partition);
+ return -1;
+ }
+
+ MtdWriteContext* ctx = mtd_write_partition(mtd);
+ if (ctx == NULL) {
+ printf("failed to init mtd partition \"%s\" for writing\n", partition);
+ return -1;
+ }
+
+ size_t written = mtd_write_data(ctx, reinterpret_cast<const char*>(data), len);
+ if (written != len) {
+ printf("only wrote %zu of %zu bytes to MTD %s\n", written, len, partition);
+ mtd_write_close(ctx);
+ return -1;
+ }
+
+ if (mtd_erase_blocks(ctx, -1) < 0) {
+ printf("error finishing mtd write of %s\n", partition);
+ mtd_write_close(ctx);
+ return -1;
+ }
+
+ if (mtd_write_close(ctx)) {
+ printf("error closing mtd write of %s\n", partition);
+ return -1;
+ }
+ break;
+ }
- fd.reset(ota_open(partition, O_RDWR));
- if (fd == -1) {
- printf("failed to reopen %s for retry write && verify: %s\n", partition, strerror(errno));
- return -1;
+ case EMMC: {
+ size_t start = 0;
+ bool success = false;
+ unique_fd fd(ota_open(partition, O_RDWR | O_SYNC));
+ if (fd < 0) {
+ printf("failed to open %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+
+ for (size_t attempt = 0; attempt < 2; ++attempt) {
+ if (TEMP_FAILURE_RETRY(lseek(fd, start, SEEK_SET)) == -1) {
+ printf("failed seek on %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+ while (start < len) {
+ size_t to_write = len - start;
+ if (to_write > 1<<20) to_write = 1<<20;
+
+ ssize_t written = TEMP_FAILURE_RETRY(ota_write(fd, data+start, to_write));
+ if (written == -1) {
+ printf("failed write writing to %s: %s\n", partition, strerror(errno));
+ return -1;
+ }
+ start += written;
+ }
+ if (ota_fsync(fd) != 0) {
+ printf("failed to sync to %s (%s)\n", partition, strerror(errno));
+ return -1;
+ }
+ if (ota_close(fd) != 0) {
+ printf("failed to close %s (%s)\n", partition, strerror(errno));
+ return -1;
+ }
+ unique_fd fd(ota_open(partition, O_RDONLY));
+ if (fd < 0) {
+ printf("failed to reopen %s for verify (%s)\n", partition, strerror(errno));
+ return -1;
+ }
+
+ // Drop caches so our subsequent verification read
+ // won't just be reading the cache.
+ sync();
+ unique_fd dc(ota_open("/proc/sys/vm/drop_caches", O_WRONLY));
+ if (TEMP_FAILURE_RETRY(ota_write(dc, "3\n", 2)) == -1) {
+ printf("write to /proc/sys/vm/drop_caches failed: %s\n", strerror(errno));
+ } else {
+ printf(" caches dropped\n");
+ }
+ ota_close(dc);
+ sleep(1);
+
+ // verify
+ if (TEMP_FAILURE_RETRY(lseek(fd, 0, SEEK_SET)) == -1) {
+ printf("failed to seek back to beginning of %s: %s\n",
+ partition, strerror(errno));
+ return -1;
+ }
+ unsigned char buffer[4096];
+ start = len;
+ for (size_t p = 0; p < len; p += sizeof(buffer)) {
+ size_t to_read = len - p;
+ if (to_read > sizeof(buffer)) {
+ to_read = sizeof(buffer);
+ }
+
+ size_t so_far = 0;
+ while (so_far < to_read) {
+ ssize_t read_count =
+ TEMP_FAILURE_RETRY(ota_read(fd, buffer+so_far, to_read-so_far));
+ if (read_count == -1) {
+ printf("verify read error %s at %zu: %s\n",
+ partition, p, strerror(errno));
+ return -1;
+ }
+ if (static_cast<size_t>(read_count) < to_read) {
+ printf("short verify read %s at %zu: %zd %zu %s\n",
+ partition, p, read_count, to_read, strerror(errno));
+ }
+ so_far += read_count;
+ }
+
+ if (memcmp(buffer, data+p, to_read) != 0) {
+ printf("verification failed starting at %zu\n", p);
+ start = p;
+ break;
+ }
+ }
+
+ if (start == len) {
+ printf("verification read succeeded (attempt %zu)\n", attempt+1);
+ success = true;
+ break;
+ }
+ }
+
+ if (!success) {
+ printf("failed to verify after all attempts\n");
+ return -1;
+ }
+
+ if (ota_close(fd) != 0) {
+ printf("error closing %s (%s)\n", partition, strerror(errno));
+ return -1;
+ }
+ sync();
+ break;
+ }
}
- }
-
- if (!success) {
- printf("failed to verify after all attempts\n");
- return -1;
- }
- if (ota_close(fd) == -1) {
- printf("error closing %s: %s\n", partition, strerror(errno));
- return -1;
- }
- sync();
-
- return 0;
+ return 0;
}
// Take a string 'str' of 40 hex digits and parse it into the 20