diff options
-rw-r--r-- | partition_tools/Android.bp | 76 | ||||
-rw-r--r-- | partition_tools/lpdump.cc | 126 | ||||
-rw-r--r-- | partition_tools/lpflash.cc | 56 | ||||
-rw-r--r-- | partition_tools/lpmake.cc | 178 |
4 files changed, 436 insertions, 0 deletions
diff --git a/partition_tools/Android.bp b/partition_tools/Android.bp new file mode 100644 index 00000000..265ee666 --- /dev/null +++ b/partition_tools/Android.bp @@ -0,0 +1,76 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_defaults { + name: "lp_defaults", + cflags: [ + "-Werror", + "-Wextra", + ], + target: { + linux_bionic: { + enabled: true, + }, + }, +} + +cc_binary { + name: "lpdump", + defaults: ["lp_defaults"], + host_supported: true, + static_libs: [ + "libbase", + "libcrypto", + "libcrypto_utils", + "liblog", + "liblp", + ], + srcs: [ + "lpdump.cc", + ], +} + +cc_binary { + name: "lpmake", + defaults: ["lp_defaults"], + host_supported: true, + static_libs: [ + "libbase", + "libcrypto", + "libcrypto_utils", + "liblog", + "liblp", + ], + srcs: [ + "lpmake.cc", + ], +} + +cc_binary { + name: "lpflash", + defaults: ["lp_defaults"], + host_supported: true, + static_libs: [ + "libbase", + "libcrypto", + "libcrypto_utils", + "liblog", + "liblp", + ], + srcs: [ + "lpflash.cc", + ], +} diff --git a/partition_tools/lpdump.cc b/partition_tools/lpdump.cc new file mode 100644 index 00000000..c54119a3 --- /dev/null +++ b/partition_tools/lpdump.cc @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <getopt.h> +#include <inttypes.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sysexits.h> +#include <unistd.h> + +#include <string> + +#include <android-base/parseint.h> +#include <liblp/reader.h> + +using namespace android; +using namespace android::fs_mgr; + +static int usage(int /* argc */, char* argv[]) { + fprintf(stderr, + "%s - command-line tool for dumping Android Logical Partition images.\n" + "\n" + "Usage:\n" + " %s [-s,--slot] file-or-device\n" + "\n" + "Options:\n" + " -s, --slot=N Slot number or suffix.\n", + argv[0], argv[0]); + return EX_USAGE; +} + +static std::string BuildAttributeString(uint32_t attrs) { + return (attrs & LP_PARTITION_ATTR_READONLY) ? "readonly" : "none"; +} + +static bool IsBlockDevice(const char* file) { + struct stat s; + return !stat(file, &s) && S_ISBLK(s.st_mode); +} + +int main(int argc, char* argv[]) { + struct option options[] = { + { "slot", required_argument, nullptr, 's' }, + { "help", no_argument, nullptr, 'h' }, + { nullptr, 0, nullptr, 0 }, + }; + + int rv; + int index; + uint32_t slot = 0; + while ((rv = getopt_long_only(argc, argv, "s:h", options, &index)) != -1) { + switch (rv) { + case 'h': + return usage(argc, argv); + case 's': + if (!android::base::ParseUint(optarg, &slot)) { + slot = SlotNumberForSlotSuffix(optarg); + } + break; + } + } + + if (optind >= argc) { + return usage(argc, argv); + } + const char* file = argv[optind++]; + + std::unique_ptr<LpMetadata> pt; + if (IsBlockDevice(file)) { + pt = ReadMetadata(file, slot); + } else { + pt = ReadFromImageFile(file); + } + if (!pt) { + fprintf(stderr, "Failed to read metadata.\n"); + return EX_NOINPUT; + } + + printf("Metadata version: %u.%u\n", pt->header.major_version, pt->header.minor_version); + printf("Metadata size: %u bytes\n", pt->header.header_size + pt->header.tables_size); + printf("Metadata max size: %u bytes\n", pt->geometry.metadata_max_size); + printf("Metadata slot count: %u\n", pt->geometry.metadata_slot_count); + printf("First logical sector: %" PRIu64 "\n", pt->geometry.first_logical_sector); + printf("Last logical sector: %" PRIu64 "\n", pt->geometry.last_logical_sector); + printf("Partition table:\n"); + printf("------------------------\n"); + + for (const auto& partition : pt->partitions) { + std::string name = GetPartitionName(partition); + std::string guid = GetPartitionGuid(partition); + printf(" Name: %s\n", name.c_str()); + printf(" GUID: %s\n", guid.c_str()); + printf(" Attributes: %s\n", BuildAttributeString(partition.attributes).c_str()); + printf(" Extents:\n"); + uint64_t first_sector = 0; + for (size_t i = 0; i < partition.num_extents; i++) { + const LpMetadataExtent& extent = pt->extents[partition.first_extent_index + i]; + printf(" %" PRIu64 " .. %" PRIu64 " ", first_sector, + (first_sector + extent.num_sectors - 1)); + first_sector += extent.num_sectors; + if (extent.target_type == LP_TARGET_TYPE_LINEAR) { + printf("linear %" PRIu64, extent.target_data); + } else if (extent.target_type == LP_TARGET_TYPE_ZERO) { + printf("zero"); + } + printf("\n"); + } + printf("------------------------\n"); + } + + return EX_OK; +} diff --git a/partition_tools/lpflash.cc b/partition_tools/lpflash.cc new file mode 100644 index 00000000..83e5008d --- /dev/null +++ b/partition_tools/lpflash.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <sysexits.h> + +#include <string> + +#include <liblp/reader.h> +#include <liblp/writer.h> + +using namespace android; +using namespace android::fs_mgr; + +/* Prints program usage to |where|. */ +static int usage(int /* argc */, char* argv[]) { + fprintf(stderr, + "%s - command-line tool for dumping Android Logical Partition images.\n" + "\n" + "Usage:\n" + " %s [block-device] [img-file]\n", + argv[0], argv[0]); + return EX_USAGE; +} + +int main(int argc, char* argv[]) { + if (argc != 3) { + return usage(argc, argv); + } + + std::unique_ptr<LpMetadata> pt = ReadFromImageFile(argv[2]); + if (!pt) { + printf("Failed to read image file.\n"); + return EX_NOINPUT; + } + + if (!WritePartitionTable(argv[1], *pt.get(), SyncMode::Flash, 0)) { + printf("Failed to flash partition table.\n"); + return EX_SOFTWARE; + } + printf("Successfully flashed partition table.\n"); + return EX_OK; +} diff --git a/partition_tools/lpmake.cc b/partition_tools/lpmake.cc new file mode 100644 index 00000000..016b32d7 --- /dev/null +++ b/partition_tools/lpmake.cc @@ -0,0 +1,178 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <getopt.h> +#include <inttypes.h> +#include <stdio.h> +#include <sysexits.h> + +#include <memory> + +#include <android-base/parseint.h> +#include <android-base/strings.h> +#include <liblp/builder.h> +#include <liblp/writer.h> + +using namespace android; +using namespace android::fs_mgr; + +/* Prints program usage to |where|. */ +static int usage(int /* argc */, char* argv[]) { + fprintf(stderr, + "%s - command-line tool for creating Android Logical Partition images.\n" + "\n" + "Usage:\n" + " %s [options]\n" + "\n" + "Required options:\n" + " -d,--device-size=SIZE Size of the block device for logical 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" + " -o,--output=FILE Output file.\n" + "\n" + "Partition format:\n" + " <name>:<guid>:<attributes>:<size>\n" + " Attrs must be 'none' or 'readonly'.\n", + argv[0], argv[0]); + return EX_USAGE; +} + +int main(int argc, char* argv[]) { + struct option options[] = { + { "device-size", required_argument, nullptr, 'd' }, + { "metadata-size", required_argument, nullptr, 'm' }, + { "metadata-slots", required_argument, nullptr, 's' }, + { "partition", required_argument, nullptr, 'p' }, + { "output", required_argument, nullptr, 'o' }, + { "help", no_argument, nullptr, 'h' }, + { nullptr, 0, nullptr, 0 }, + }; + + uint64_t blockdevice_size = 0; + uint32_t metadata_size = 0; + uint32_t metadata_slots = 0; + std::string output_path; + std::vector<std::string> partitions; + + int rv; + int index; + while ((rv = getopt_long_only(argc, argv, "d:m:s:p:o:h", options, &index)) != -1) { + switch (rv) { + case 'h': + return usage(argc, argv); + case 'd': + if (!android::base::ParseUint(optarg, &blockdevice_size)) { + fprintf(stderr, "Invalid argument to --device-size.\n"); + return EX_USAGE; + } + break; + case 'm': + if (!android::base::ParseUint(optarg, &metadata_size)) { + fprintf(stderr, "Invalid argument to --metadata-size.\n"); + return EX_USAGE; + } + break; + case 's': + if (!android::base::ParseUint(optarg, &metadata_slots)) { + fprintf(stderr, "Invalid argument to --metadata-slots.\n"); + return EX_USAGE; + } + break; + case 'p': + partitions.push_back(optarg); + break; + case 'o': + output_path = optarg; + break; + default: + break; + } + } + + // Check for empty arguments so we can print a more helpful message rather + // than error on each individual missing argument. + if (optind == 1) { + return usage(argc, argv); + } + + if (!blockdevice_size) { + fprintf(stderr, "--device-size needs more than 0 bytes of disk space.\n"); + return EX_USAGE; + } + if (!metadata_size) { + fprintf(stderr, "--metadata-size must be more than 0 bytes.\n"); + return EX_USAGE; + } + if (!metadata_slots) { + fprintf(stderr, "--metadata-slots must be more than 0.\n"); + return EX_USAGE; + } + if (output_path.empty()) { + fprintf(stderr, "--output must specify a valid path.\n"); + return EX_USAGE; + } + if (partitions.empty()) { + fprintf(stderr, "Partition table must have at least one entry.\n"); + return EX_USAGE; + } + + std::unique_ptr<MetadataBuilder> builder = + MetadataBuilder::New(blockdevice_size, metadata_size, metadata_slots); + + 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.length()) { + fprintf(stderr, "Partition must have a valid name.\n"); + return EX_USAGE; + } + + uint64_t size; + if (!android::base::ParseUint(parts[3].c_str(), &size)) { + fprintf(stderr, "Partition must have a valid size.\n"); + return EX_USAGE; + } + + uint32_t attribute_flags = 0; + std::string attributes = parts[2]; + 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; + } + + Partition* partition = builder->AddPartition(name, parts[1], attribute_flags); + if (!builder->GrowPartition(partition, size)) { + fprintf(stderr, "Not enough space on device for partition %s with size %" PRIu64 "\n", + name.c_str(), size); + return EX_SOFTWARE; + } + } + + std::unique_ptr<LpMetadata> metadata = builder->Export(); + if (!WriteToImageFile(output_path.c_str(), *metadata.get())) { + return EX_CANTCREAT; + } + + return EX_OK; +} |