summaryrefslogtreecommitdiff
path: root/partition_tools/lpdump.cc
diff options
context:
space:
mode:
Diffstat (limited to 'partition_tools/lpdump.cc')
-rw-r--r--partition_tools/lpdump.cc278
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;
}