From 674ae9ee88a487f18ec400add8c3d50a1db779e2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 5 Sep 2019 17:57:20 -0700 Subject: [PATCH] lpdump: Refactor how lpdump reads metadata. This patch prepares lpdump for the addition of an "--all" option to dump all metadata slots. - The slot and super partition name are now determined ahead of time, rather than as part of reading metadata. - The custom IPartitionOpener has been removed as it served no purpose. - The -e option has been removed in favor of IsEmptySuperImage(). - Metadata spew has been factored into a separate function. Bug: 140204341 Test: manual test Change-Id: I810a5f042870f7e072a8939bebe99b8707235f43 --- partition_tools/lpdump.cc | 181 +++++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 83 deletions(-) diff --git a/partition_tools/lpdump.cc b/partition_tools/lpdump.cc index 302e2840..26923edf 100644 --- a/partition_tools/lpdump.cc +++ b/partition_tools/lpdump.cc @@ -56,8 +56,6 @@ static int usage(int /* argc */, char* argv[], std::ostream& cerr) { "Options:\n" " -s, --slot=N Slot number or suffix.\n" " -j, --json Print in JSON format.\n" - " -e, --is-super-empty\n" - " The given file is a super_empty.img.\n" " -d, --dump-metadata-size\n" " Print the space reserved for metadata to stdout\n" " in bytes.\n"; @@ -88,11 +86,6 @@ static std::string BuildBlockDeviceFlagString(uint32_t flags) { return BuildFlagString(strings); } -static bool IsBlockDevice(const char* file) { - struct stat s; - return !stat(file, &s) && S_ISBLK(s.st_mode); -} - // Reimplementation of fs_mgr_get_slot_suffix() without reading // kernel commandline. static std::string GetSlotSuffix() { @@ -101,7 +94,7 @@ static std::string GetSlotSuffix() { // Reimplementation of fs_mgr_get_super_partition_name() without reading // kernel commandline. Always return the super partition at current slot. -static std::string GetSuperPartionName() { +static std::string GetSuperPartitionName() { std::string super_partition = base::GetProperty("ro.boot.super_partition", ""); if (super_partition.empty()) { return LP_METADATA_DEFAULT_PARTITION_NAME; @@ -253,8 +246,8 @@ static int PrintJson(const LpMetadata* metadata, std::ostream& cout, return EX_OK; } -static int DumpMetadataSize(const LpMetadata* metadata, std::ostream& cout) { - auto super_device = GetMetadataSuperBlockDevice(*metadata); +static int DumpMetadataSize(const LpMetadata& metadata, std::ostream& cout) { + auto super_device = GetMetadataSuperBlockDevice(metadata); uint64_t metadata_size = super_device->first_logical_sector * LP_SECTOR_SIZE; cout << metadata_size << std::endl; return EX_OK; @@ -277,6 +270,69 @@ public: } }; +static void PrintMetadata(const LpMetadata& pt, std::ostream& cout) { + cout << "Metadata version: " << pt.header.major_version << "." << pt.header.minor_version + << "\n"; + cout << "Metadata size: " << (pt.header.header_size + pt.header.tables_size) << " bytes\n"; + cout << "Metadata max size: " << pt.geometry.metadata_max_size << " bytes\n"; + cout << "Metadata slot count: " << pt.geometry.metadata_slot_count << "\n"; + cout << "Partition table:\n"; + cout << "------------------------\n"; + + for (const auto& partition : pt.partitions) { + std::string name = GetPartitionName(partition); + std::string group_name = GetPartitionGroupName(pt.groups[partition.group_index]); + cout << " Name: " << name << "\n"; + cout << " Group: " << group_name << "\n"; + cout << " Attributes: " << BuildAttributeString(partition.attributes) << "\n"; + cout << " 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]; + cout << " " << first_sector << " .. " << (first_sector + extent.num_sectors - 1) + << " "; + first_sector += extent.num_sectors; + if (extent.target_type == LP_TARGET_TYPE_LINEAR) { + const auto& block_device = pt.block_devices[extent.target_source]; + std::string device_name = GetBlockDevicePartitionName(block_device); + cout << "linear " << device_name.c_str() << " " << extent.target_data; + } else if (extent.target_type == LP_TARGET_TYPE_ZERO) { + cout << "zero"; + } + cout << "\n"; + } + cout << "------------------------\n"; + } + + cout << "Block device table:\n"; + cout << "------------------------\n"; + for (const auto& block_device : pt.block_devices) { + std::string partition_name = GetBlockDevicePartitionName(block_device); + cout << " Partition name: " << partition_name << "\n"; + cout << " First sector: " << block_device.first_logical_sector << "\n"; + cout << " Size: " << block_device.size << " bytes\n"; + cout << " Flags: " << BuildBlockDeviceFlagString(block_device.flags) << "\n"; + cout << "------------------------\n"; + } + + cout << "Group table:\n"; + cout << "------------------------\n"; + for (const auto& group : pt.groups) { + std::string group_name = GetPartitionGroupName(group); + cout << " Name: " << group_name << "\n"; + cout << " Maximum size: " << group.maximum_size << " bytes\n"; + cout << " Flags: " << BuildGroupFlagString(group.flags) << "\n"; + cout << "------------------------\n"; + } +} + +static std::unique_ptr ReadDeviceOrFile(const std::string& path, uint32_t slot) { + if (IsEmptySuperImage(path)) { + return ReadFromImageFile(path); + } + return ReadMetadata(path, slot); +} + int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { // clang-format off struct option options[] = { @@ -294,22 +350,25 @@ int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { int rv; int index; - uint32_t slot = 0; bool json = false; - bool is_empty = false; bool dump_metadata_size = false; + std::optional slot; while ((rv = getopt_long_only(argc, argv, "s:jhde", options, &index)) != -1) { switch (rv) { case 'h': usage(argc, argv, cerr); return EX_OK; - case 's': - if (!android::base::ParseUint(optarg, &slot)) { + case 's': { + uint32_t slot_arg; + if (android::base::ParseUint(optarg, &slot_arg)) { + slot = slot_arg; + } else { slot = SlotNumberForSlotSuffix(optarg); } break; + } case 'e': - is_empty = true; + // This is ignored, we now derive whether it's empty automatically. break; case 'd': dump_metadata_size = true; @@ -323,28 +382,34 @@ int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { } } - std::unique_ptr pt; +#ifdef __ANDROID__ + // Use the current slot as a default for A/B devices. + auto slot_suffix = GetSlotSuffix(); + if (!slot.has_value() && !slot_suffix.empty()) { + slot = SlotNumberForSlotSuffix(slot_suffix); + } +#endif + + // If we still haven't determined a slot yet, use the first one. + if (!slot.has_value()) { + slot = 0; + } + + // Determine the path to the super partition (or image). + std::string super_path; if (optind < argc) { - FileOrBlockDeviceOpener opener; - const char* file = argv[optind++]; - if (!is_empty) { - pt = ReadMetadata(opener, file, slot); - } - if (!pt && !IsBlockDevice(file)) { - pt = ReadFromImageFile(file); - } + super_path = argv[optind++]; } else { #ifdef __ANDROID__ - if (is_empty) { - return usage(argc, argv, cerr); - } - auto slot_number = SlotNumberForSlotSuffix(GetSlotSuffix()); - pt = ReadMetadata(GetSuperPartionName(), slot_number); + super_path = GetSuperPartitionName(); #else + cerr << "Must specify a super partition image.\n"; return usage(argc, argv, cerr); #endif } + auto pt = ReadDeviceOrFile(super_path, slot.value()); + // --json option doesn't require metadata to be present. if (json) { return PrintJson(pt.get(), cout, cerr); @@ -356,63 +421,13 @@ int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { } if (dump_metadata_size) { - return DumpMetadataSize(pt.get(), cout); - } - - cout << "Metadata version: " << pt->header.major_version << "." << pt->header.minor_version - << "\n"; - cout << "Metadata size: " << (pt->header.header_size + pt->header.tables_size) << " bytes\n"; - cout << "Metadata max size: " << pt->geometry.metadata_max_size << " bytes\n"; - cout << "Metadata slot count: " << pt->geometry.metadata_slot_count << "\n"; - cout << "Partition table:\n"; - cout << "------------------------\n"; - - for (const auto& partition : pt->partitions) { - std::string name = GetPartitionName(partition); - std::string group_name = GetPartitionGroupName(pt->groups[partition.group_index]); - cout << " Name: " << name << "\n"; - cout << " Group: " << group_name << "\n"; - cout << " Attributes: " << BuildAttributeString(partition.attributes) << "\n"; - cout << " 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]; - cout << " " << first_sector << " .. " << (first_sector + extent.num_sectors - 1) - << " "; - first_sector += extent.num_sectors; - if (extent.target_type == LP_TARGET_TYPE_LINEAR) { - const auto& block_device = pt->block_devices[extent.target_source]; - std::string device_name = GetBlockDevicePartitionName(block_device); - cout << "linear " << device_name.c_str() << " " << extent.target_data; - } else if (extent.target_type == LP_TARGET_TYPE_ZERO) { - cout << "zero"; - } - cout << "\n"; - } - cout << "------------------------\n"; - } - - cout << "Block device table:\n"; - cout << "------------------------\n"; - for (const auto& block_device : pt->block_devices) { - std::string partition_name = GetBlockDevicePartitionName(block_device); - cout << " Partition name: " << partition_name << "\n"; - cout << " First sector: " << block_device.first_logical_sector << "\n"; - cout << " Size: " << block_device.size << " bytes\n"; - cout << " Flags: " << BuildBlockDeviceFlagString(block_device.flags) << "\n"; - cout << "------------------------\n"; + return DumpMetadataSize(*pt.get(), cout); } - cout << "Group table:\n"; - cout << "------------------------\n"; - for (const auto& group : pt->groups) { - std::string group_name = GetPartitionGroupName(group); - cout << " Name: " << group_name << "\n"; - cout << " Maximum size: " << group.maximum_size << " bytes\n"; - cout << " Flags: " << BuildGroupFlagString(group.flags) << "\n"; - cout << "------------------------\n"; + if (!IsEmptySuperImage(super_path)) { + cout << "Slot " << slot.value() << ":\n"; } - + PrintMetadata(*pt.get(), cout); return EX_OK; } -- 2.11.0