diff options
Diffstat (limited to 'partition_tools/lpdump.cc')
-rw-r--r-- | partition_tools/lpdump.cc | 278 |
1 files changed, 69 insertions, 209 deletions
diff --git a/partition_tools/lpdump.cc b/partition_tools/lpdump.cc index 2eb9f1fe..1b607f8a 100644 --- a/partition_tools/lpdump.cc +++ b/partition_tools/lpdump.cc @@ -23,7 +23,6 @@ #include <sysexits.h> #include <unistd.h> -#include <algorithm> #include <iostream> #include <optional> #include <regex> @@ -56,11 +55,7 @@ static int usage(int /* argc */, char* argv[], std::ostream& cerr) { "\n" "Options:\n" " -s, --slot=N Slot number or suffix.\n" - " -j, --json Print in JSON format.\n" - " -d, --dump-metadata-size\n" - " Print the space reserved for metadata to stdout\n" - " in bytes.\n" - " -a, --all Dump all slots (not available in JSON mode).\n"; + " -j, --json Print in JSON format.\n"; return EX_USAGE; } @@ -72,7 +67,6 @@ static std::string BuildAttributeString(uint32_t attrs) { std::vector<std::string> strings; if (attrs & LP_PARTITION_ATTR_READONLY) strings.emplace_back("readonly"); if (attrs & LP_PARTITION_ATTR_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed"); - if (attrs & LP_PARTITION_ATTR_UPDATED) strings.emplace_back("updated"); return BuildFlagString(strings); } @@ -88,6 +82,11 @@ 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() { @@ -96,14 +95,11 @@ 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 GetSuperPartitionName(const std::optional<uint32_t>& slot = {}) { +static std::string GetSuperPartionName() { std::string super_partition = base::GetProperty("ro.boot.super_partition", ""); if (super_partition.empty()) { return LP_METADATA_DEFAULT_PARTITION_NAME; } - if (slot.has_value()) { - return super_partition + SlotSuffixForSlotNumber(slot.value()); - } return super_partition + GetSlotSuffix(); } @@ -251,13 +247,6 @@ 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); - uint64_t metadata_size = super_device->first_logical_sector * LP_SECTOR_SIZE; - cout << metadata_size << std::endl; - return EX_OK; -} - class FileOrBlockDeviceOpener final : public PartitionOpener { public: android::base::unique_fd Open(const std::string& path, int flags) const override { @@ -275,108 +264,12 @@ public: } }; -std::optional<std::tuple<std::string, uint64_t>> -ParseLinearExtentData(const LpMetadata& pt, const LpMetadataExtent& extent) { - if (extent.target_type != LP_TARGET_TYPE_LINEAR) { - return std::nullopt; - } - const auto& block_device = pt.block_devices[extent.target_source]; - std::string device_name = GetBlockDevicePartitionName(block_device); - return std::make_tuple(std::move(device_name), extent.target_data); -} - -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"; - - std::vector<std::tuple<std::string, const LpMetadataExtent*>> extents; - - 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"; - } - extents.push_back(std::make_tuple(name, &extent)); - cout << "\n"; - } - cout << "------------------------\n"; - } - - std::sort(extents.begin(), extents.end(), [&](const auto& x, const auto& y) { - auto x_data = ParseLinearExtentData(pt, *std::get<1>(x)); - auto y_data = ParseLinearExtentData(pt, *std::get<1>(y)); - return x_data < y_data; - }); - - cout << "Super partition layout:\n"; - cout << "------------------------\n"; - for (auto&& [name, extent] : extents) { - auto data = ParseLinearExtentData(pt, *extent); - if (!data) continue; - auto&& [block_device, offset] = *data; - cout << block_device << ": " << offset << " .. " << (offset + extent->num_sectors) - << ": " << name << " (" << extent->num_sectors << " sectors)\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<LpMetadata> 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[] = { - { "all", no_argument, nullptr, 'a' }, { "slot", required_argument, nullptr, 's' }, { "help", no_argument, nullptr, 'h' }, { "json", no_argument, nullptr, 'j' }, - { "dump-metadata-size", no_argument, nullptr, 'd' }, - { "is-super-empty", no_argument, nullptr, 'e' }, { nullptr, 0, nullptr, 0 }, }; // clang-format on @@ -386,87 +279,40 @@ int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { int rv; int index; + uint32_t slot = 0; bool json = false; - bool dump_metadata_size = false; - bool dump_all = false; - std::optional<uint32_t> slot; - while ((rv = getopt_long_only(argc, argv, "s:jhde", options, &index)) != -1) { + while ((rv = getopt_long_only(argc, argv, "s:jh", options, &index)) != -1) { switch (rv) { - case 'a': - dump_all = true; - break; case 'h': - usage(argc, argv, cerr); - return EX_OK; - case 's': { - uint32_t slot_arg; - if (android::base::ParseUint(optarg, &slot_arg)) { - slot = slot_arg; - } else { + return usage(argc, argv, cerr); + case 's': + if (!android::base::ParseUint(optarg, &slot)) { slot = SlotNumberForSlotSuffix(optarg); } break; - } - case 'e': - // This is ignored, we now derive whether it's empty automatically. - break; - case 'd': - dump_metadata_size = true; - break; case 'j': json = true; break; - case '?': - case ':': - return usage(argc, argv, cerr); } } - if (dump_all) { - if (slot.has_value()) { - cerr << "Cannot specify both --all and --slot.\n"; - return usage(argc, argv, cerr); - } - if (json) { - cerr << "Cannot specify both --all and --json.\n"; - return usage(argc, argv, cerr); + std::unique_ptr<LpMetadata> pt; + if (optind < argc) { + FileOrBlockDeviceOpener opener; + const char* file = argv[optind++]; + pt = ReadMetadata(opener, file, slot); + if (!pt && !IsBlockDevice(file)) { + pt = ReadFromImageFile(file); } - - // When dumping everything always start from the first slot. - slot = 0; - } - -#ifdef __ANDROID__ - // Use the current slot as a default for A/B devices. - auto current_slot_suffix = GetSlotSuffix(); - if (!slot.has_value() && !current_slot_suffix.empty()) { - slot = SlotNumberForSlotSuffix(current_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). If an explicit - // path is given, we use it for everything. Otherwise, we will infer it - // at the time we need to read metadata. - std::string super_path; - bool override_super_name = (optind < argc); - if (override_super_name) { - super_path = argv[optind++]; } else { #ifdef __ANDROID__ - super_path = GetSuperPartitionName(slot); + auto slot_number = SlotNumberForSlotSuffix(GetSlotSuffix()); + pt = ReadMetadata(GetSuperPartionName(), slot_number); #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); @@ -477,46 +323,60 @@ int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) { return EX_NOINPUT; } - 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"; - // When running on the device, we can check the slot count. Otherwise we - // use the # of metadata slots. (There is an extra slot we don't want to - // dump because it is currently unused.) -#ifdef __ANDROID__ - uint32_t num_slots = current_slot_suffix.empty() ? 1 : 2; - if (dump_all && num_slots > 1) { - cout << "Current slot: " << current_slot_suffix << "\n"; - } -#else - uint32_t num_slots = pt->geometry.metadata_slot_count; -#endif - // Empty images only have one slot. - if (IsEmptySuperImage(super_path)) { - num_slots = 1; + 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"; } - if (num_slots > 1) { - cout << "Slot " << slot.value() << ":\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"; } - PrintMetadata(*pt.get(), cout); - - if (dump_all) { - for (uint32_t i = 1; i < num_slots; i++) { - if (!override_super_name) { - super_path = GetSuperPartitionName(i); - } - - pt = ReadDeviceOrFile(super_path, i); - if (!pt) { - continue; - } - cout << "\nSlot " << i << ":\n"; - PrintMetadata(*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"; } + return EX_OK; } |