summaryrefslogtreecommitdiff
path: root/partition_tools/lpmake.cc
diff options
context:
space:
mode:
Diffstat (limited to 'partition_tools/lpmake.cc')
-rw-r--r--partition_tools/lpmake.cc120
1 files changed, 80 insertions, 40 deletions
diff --git a/partition_tools/lpmake.cc b/partition_tools/lpmake.cc
index 1b879636..ca9e62f9 100644
--- a/partition_tools/lpmake.cc
+++ b/partition_tools/lpmake.cc
@@ -19,9 +19,11 @@
#include <stdio.h>
#include <sysexits.h>
+#include <algorithm>
#include <memory>
#include <android-base/parseint.h>
+#include <android-base/result.h>
#include <android-base/strings.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
@@ -29,6 +31,9 @@
using namespace android;
using namespace android::fs_mgr;
+using android::base::Error;
+using android::base::Result;
+
/* Prints program usage to |where|. */
static int usage(int /* argc */, char* argv[]) {
fprintf(stderr,
@@ -38,7 +43,10 @@ static int usage(int /* argc */, char* argv[]) {
" %s [options]\n"
"\n"
"Required options:\n"
- " -d,--device-size=SIZE Size of the block device for logical partitions.\n"
+ " -d,--device-size=[SIZE|auto] Size of the block device for logical partitions.\n"
+ " Can be set to auto to automatically calculate the\n"
+ " minimum size, the sum of partition sizes plus\n"
+ " metadata-size times the number of partitions.\n"
" -m,--metadata-size=SIZE Maximum size to reserve for partition metadata.\n"
" -s,--metadata-slots=COUNT Number of slots to store metadata copies.\n"
" -p,--partition=DATA Add a partition given the data, see below.\n"
@@ -108,6 +116,56 @@ enum class Option : int {
kForceFullImage = 'F',
};
+struct PartitionInfo {
+ std::string name;
+ uint64_t size;
+ uint32_t attribute_flags;
+ std::string group_name;
+
+ static Result<PartitionInfo> Parse(const char* arg) {
+ std::vector<std::string> parts = android::base::Split(arg, ":");
+ if (parts.size() > 4) {
+ return Error() << "Partition info has invalid formatting.";
+ }
+
+ std::string name = parts[0];
+ if (name.empty()) {
+ return Error() << "Partition must have a valid name.";
+ }
+
+ uint64_t size;
+ if (!android::base::ParseUint(parts[2].c_str(), &size)) {
+ return Error() << "Partition must have a valid size.";
+ }
+
+ uint32_t attribute_flags = 0;
+ std::string attributes = parts[1];
+ if (attributes == "readonly") {
+ attribute_flags |= LP_PARTITION_ATTR_READONLY;
+ } else if (attributes != "none") {
+ return Error() << "Attribute not recognized: " << attributes;
+ }
+
+ std::string group_name = "default";
+ if (parts.size() >= 4) {
+ group_name = parts[3];
+ }
+
+ return PartitionInfo{name, size, attribute_flags, group_name};
+ }
+};
+
+static uint64_t CalculateBlockDeviceSize(uint32_t alignment, uint32_t metadata_size,
+ const std::vector<PartitionInfo>& partitions) {
+ uint64_t ret = std::max(alignment, LP_PARTITION_RESERVED_BYTES +
+ (LP_METADATA_GEOMETRY_SIZE + metadata_size) * 2) +
+ partitions.size() * alignment;
+ for (const auto& partition_info : partitions) {
+ ret += partition_info.size;
+ }
+ return ret;
+}
+
int main(int argc, char* argv[]) {
struct option options[] = {
{ "device-size", required_argument, nullptr, (int)Option::kDeviceSize },
@@ -138,7 +196,7 @@ int main(int argc, char* argv[]) {
uint32_t block_size = 4096;
std::string super_name = "super";
std::string output_path;
- std::vector<std::string> partitions;
+ std::vector<PartitionInfo> partitions;
std::vector<std::string> groups;
std::vector<BlockDeviceInfo> block_devices;
std::map<std::string, std::string> images;
@@ -147,6 +205,7 @@ int main(int argc, char* argv[]) {
bool auto_slot_suffixing = false;
bool force_full_image = false;
bool virtual_ab = false;
+ bool auto_blockdevice_size = false;
int rv;
int index;
@@ -155,7 +214,10 @@ int main(int argc, char* argv[]) {
case Option::kHelp:
return usage(argc, argv);
case Option::kDeviceSize:
- if (!android::base::ParseUint(optarg, &blockdevice_size) || !blockdevice_size) {
+ if (strcmp(optarg, "auto") == 0) {
+ auto_blockdevice_size = true;
+ } else if (!android::base::ParseUint(optarg, &blockdevice_size) ||
+ !blockdevice_size) {
fprintf(stderr, "Invalid argument to --device-size.\n");
return EX_USAGE;
}
@@ -174,7 +236,12 @@ int main(int argc, char* argv[]) {
}
break;
case Option::kPartition:
- partitions.push_back(optarg);
+ if (auto res = PartitionInfo::Parse(optarg); !res.ok()) {
+ fprintf(stderr, "%s\n", res.error().message().c_str());
+ return EX_USAGE;
+ } else {
+ partitions.push_back(std::move(*res));
+ }
break;
case Option::kGroup:
groups.push_back(optarg);
@@ -270,6 +337,10 @@ int main(int argc, char* argv[]) {
return usage(argc, argv);
}
+ if (auto_blockdevice_size) {
+ blockdevice_size = CalculateBlockDeviceSize(alignment, metadata_size, partitions);
+ }
+
// Must specify a block device via the old method (--device-size etc) or
// via --device, but not both.
if ((has_implied_super && (!block_devices.empty() || !blockdevice_size)) ||
@@ -346,46 +417,15 @@ int main(int argc, char* argv[]) {
}
for (const auto& partition_info : partitions) {
- std::vector<std::string> parts = android::base::Split(partition_info, ":");
- if (parts.size() > 4) {
- fprintf(stderr, "Partition info has invalid formatting.\n");
- return EX_USAGE;
- }
-
- std::string name = parts[0];
- if (name.empty()) {
- fprintf(stderr, "Partition must have a valid name.\n");
- return EX_USAGE;
- }
-
- uint64_t size;
- if (!android::base::ParseUint(parts[2].c_str(), &size)) {
- fprintf(stderr, "Partition must have a valid size.\n");
- return EX_USAGE;
- }
-
- uint32_t attribute_flags = 0;
- std::string attributes = parts[1];
- if (attributes == "readonly") {
- attribute_flags |= LP_PARTITION_ATTR_READONLY;
- } else if (attributes != "none") {
- fprintf(stderr, "Attribute not recognized: %s\n", attributes.c_str());
- return EX_USAGE;
- }
-
- std::string group_name = "default";
- if (parts.size() >= 4) {
- group_name = parts[3];
- }
-
- Partition* partition = builder->AddPartition(name, group_name, attribute_flags);
+ Partition* partition = builder->AddPartition(partition_info.name, partition_info.group_name,
+ partition_info.attribute_flags);
if (!partition) {
- fprintf(stderr, "Could not add partition: %s\n", name.c_str());
+ fprintf(stderr, "Could not add partition: %s\n", partition_info.name.c_str());
return EX_SOFTWARE;
}
- if (!builder->ResizePartition(partition, size)) {
+ if (!builder->ResizePartition(partition, partition_info.size)) {
fprintf(stderr, "Not enough space on device for partition %s with size %" PRIu64 "\n",
- name.c_str(), size);
+ partition_info.name.c_str(), partition_info.size);
return EX_SOFTWARE;
}
}