xref: /aosp_15_r20/system/extras/partition_tools/lpdump.cc (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include <getopt.h>
18*288bf522SAndroid Build Coastguard Worker #include <inttypes.h>
19*288bf522SAndroid Build Coastguard Worker #include <sys/mount.h>
20*288bf522SAndroid Build Coastguard Worker #include <sys/stat.h>
21*288bf522SAndroid Build Coastguard Worker #include <sys/statvfs.h>
22*288bf522SAndroid Build Coastguard Worker #include <sys/types.h>
23*288bf522SAndroid Build Coastguard Worker #include <sysexits.h>
24*288bf522SAndroid Build Coastguard Worker #include <unistd.h>
25*288bf522SAndroid Build Coastguard Worker 
26*288bf522SAndroid Build Coastguard Worker #include <algorithm>
27*288bf522SAndroid Build Coastguard Worker #include <iostream>
28*288bf522SAndroid Build Coastguard Worker #include <optional>
29*288bf522SAndroid Build Coastguard Worker #include <regex>
30*288bf522SAndroid Build Coastguard Worker #include <string>
31*288bf522SAndroid Build Coastguard Worker #include <vector>
32*288bf522SAndroid Build Coastguard Worker 
33*288bf522SAndroid Build Coastguard Worker #include <android-base/parseint.h>
34*288bf522SAndroid Build Coastguard Worker #include <android-base/properties.h>
35*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
36*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
37*288bf522SAndroid Build Coastguard Worker #include <cutils/android_get_control_file.h>
38*288bf522SAndroid Build Coastguard Worker #include <fs_mgr.h>
39*288bf522SAndroid Build Coastguard Worker #include <libsnapshot/snapshot.h>
40*288bf522SAndroid Build Coastguard Worker #endif
41*288bf522SAndroid Build Coastguard Worker #include <jsonpb/jsonpb.h>
42*288bf522SAndroid Build Coastguard Worker #include <liblp/builder.h>
43*288bf522SAndroid Build Coastguard Worker #include <liblp/liblp.h>
44*288bf522SAndroid Build Coastguard Worker 
45*288bf522SAndroid Build Coastguard Worker #include "dynamic_partitions_device_info.pb.h"
46*288bf522SAndroid Build Coastguard Worker using namespace android;
47*288bf522SAndroid Build Coastguard Worker using namespace android::fs_mgr;
48*288bf522SAndroid Build Coastguard Worker 
usage(int,char * argv[],std::ostream & cerr)49*288bf522SAndroid Build Coastguard Worker static int usage(int /* argc */, char* argv[], std::ostream& cerr) {
50*288bf522SAndroid Build Coastguard Worker     cerr << argv[0]
51*288bf522SAndroid Build Coastguard Worker          << " - command-line tool for dumping Android Logical Partition images.\n"
52*288bf522SAndroid Build Coastguard Worker             "\n"
53*288bf522SAndroid Build Coastguard Worker             "Usage:\n"
54*288bf522SAndroid Build Coastguard Worker             "  "
55*288bf522SAndroid Build Coastguard Worker          << argv[0]
56*288bf522SAndroid Build Coastguard Worker          << " [-s <SLOT#>|--slot=<SLOT#>] [-j|--json] [FILE|DEVICE]\n"
57*288bf522SAndroid Build Coastguard Worker             "\n"
58*288bf522SAndroid Build Coastguard Worker             "Options:\n"
59*288bf522SAndroid Build Coastguard Worker             "  -s, --slot=N     Slot number or suffix.\n"
60*288bf522SAndroid Build Coastguard Worker             "  -j, --json       Print in JSON format.\n"
61*288bf522SAndroid Build Coastguard Worker             "  -d, --dump-metadata-size\n"
62*288bf522SAndroid Build Coastguard Worker             "                   Print the space reserved for metadata to stdout\n"
63*288bf522SAndroid Build Coastguard Worker             "                   in bytes.\n"
64*288bf522SAndroid Build Coastguard Worker             "  -a, --all        Dump all slots (not available in JSON mode).\n";
65*288bf522SAndroid Build Coastguard Worker     return EX_USAGE;
66*288bf522SAndroid Build Coastguard Worker }
67*288bf522SAndroid Build Coastguard Worker 
BuildFlagString(const std::vector<std::string> & strings)68*288bf522SAndroid Build Coastguard Worker static std::string BuildFlagString(const std::vector<std::string>& strings) {
69*288bf522SAndroid Build Coastguard Worker     return strings.empty() ? "none" : android::base::Join(strings, ",");
70*288bf522SAndroid Build Coastguard Worker }
71*288bf522SAndroid Build Coastguard Worker 
BuildHeaderFlagString(uint32_t flags)72*288bf522SAndroid Build Coastguard Worker static std::string BuildHeaderFlagString(uint32_t flags) {
73*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> strings;
74*288bf522SAndroid Build Coastguard Worker 
75*288bf522SAndroid Build Coastguard Worker     if (flags & LP_HEADER_FLAG_VIRTUAL_AB_DEVICE) {
76*288bf522SAndroid Build Coastguard Worker         strings.emplace_back("virtual_ab_device");
77*288bf522SAndroid Build Coastguard Worker         flags &= ~LP_HEADER_FLAG_VIRTUAL_AB_DEVICE;
78*288bf522SAndroid Build Coastguard Worker     }
79*288bf522SAndroid Build Coastguard Worker 
80*288bf522SAndroid Build Coastguard Worker     for (uint32_t i = 0; i < sizeof(flags) * 8; i++) {
81*288bf522SAndroid Build Coastguard Worker         if (!(flags & (1U << i))) {
82*288bf522SAndroid Build Coastguard Worker             continue;
83*288bf522SAndroid Build Coastguard Worker         }
84*288bf522SAndroid Build Coastguard Worker         strings.emplace_back("unknown_flag_bit_" + std::to_string(i));
85*288bf522SAndroid Build Coastguard Worker     }
86*288bf522SAndroid Build Coastguard Worker     return BuildFlagString(strings);
87*288bf522SAndroid Build Coastguard Worker }
88*288bf522SAndroid Build Coastguard Worker 
BuildAttributeString(uint32_t attrs)89*288bf522SAndroid Build Coastguard Worker static std::string BuildAttributeString(uint32_t attrs) {
90*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> strings;
91*288bf522SAndroid Build Coastguard Worker     if (attrs & LP_PARTITION_ATTR_READONLY) strings.emplace_back("readonly");
92*288bf522SAndroid Build Coastguard Worker     if (attrs & LP_PARTITION_ATTR_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
93*288bf522SAndroid Build Coastguard Worker     if (attrs & LP_PARTITION_ATTR_UPDATED) strings.emplace_back("updated");
94*288bf522SAndroid Build Coastguard Worker     if (attrs & LP_PARTITION_ATTR_DISABLED) strings.emplace_back("disabled");
95*288bf522SAndroid Build Coastguard Worker     return BuildFlagString(strings);
96*288bf522SAndroid Build Coastguard Worker }
97*288bf522SAndroid Build Coastguard Worker 
BuildGroupFlagString(uint32_t flags)98*288bf522SAndroid Build Coastguard Worker static std::string BuildGroupFlagString(uint32_t flags) {
99*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> strings;
100*288bf522SAndroid Build Coastguard Worker     if (flags & LP_GROUP_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
101*288bf522SAndroid Build Coastguard Worker     return BuildFlagString(strings);
102*288bf522SAndroid Build Coastguard Worker }
103*288bf522SAndroid Build Coastguard Worker 
BuildBlockDeviceFlagString(uint32_t flags)104*288bf522SAndroid Build Coastguard Worker static std::string BuildBlockDeviceFlagString(uint32_t flags) {
105*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> strings;
106*288bf522SAndroid Build Coastguard Worker     if (flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
107*288bf522SAndroid Build Coastguard Worker     return BuildFlagString(strings);
108*288bf522SAndroid Build Coastguard Worker }
109*288bf522SAndroid Build Coastguard Worker 
110*288bf522SAndroid Build Coastguard Worker // Reimplementation of fs_mgr_get_slot_suffix() without reading
111*288bf522SAndroid Build Coastguard Worker // kernel commandline.
GetSlotSuffix()112*288bf522SAndroid Build Coastguard Worker static std::string GetSlotSuffix() {
113*288bf522SAndroid Build Coastguard Worker     return base::GetProperty("ro.boot.slot_suffix", "");
114*288bf522SAndroid Build Coastguard Worker }
115*288bf522SAndroid Build Coastguard Worker 
116*288bf522SAndroid Build Coastguard Worker // Reimplementation of fs_mgr_get_super_partition_name() without reading
117*288bf522SAndroid Build Coastguard Worker // kernel commandline. Always return the super partition at current slot.
GetSuperPartitionName(const std::optional<uint32_t> & slot={})118*288bf522SAndroid Build Coastguard Worker static std::string GetSuperPartitionName(const std::optional<uint32_t>& slot = {}) {
119*288bf522SAndroid Build Coastguard Worker     std::string super_partition = base::GetProperty("ro.boot.super_partition", "");
120*288bf522SAndroid Build Coastguard Worker     if (super_partition.empty()) {
121*288bf522SAndroid Build Coastguard Worker         return LP_METADATA_DEFAULT_PARTITION_NAME;
122*288bf522SAndroid Build Coastguard Worker     }
123*288bf522SAndroid Build Coastguard Worker     if (slot.has_value()) {
124*288bf522SAndroid Build Coastguard Worker         return super_partition + SlotSuffixForSlotNumber(slot.value());
125*288bf522SAndroid Build Coastguard Worker     }
126*288bf522SAndroid Build Coastguard Worker     return super_partition + GetSlotSuffix();
127*288bf522SAndroid Build Coastguard Worker }
128*288bf522SAndroid Build Coastguard Worker 
RemoveSuffix(const std::string & s,const std::string & suffix)129*288bf522SAndroid Build Coastguard Worker static std::string RemoveSuffix(const std::string& s, const std::string& suffix) {
130*288bf522SAndroid Build Coastguard Worker     if (base::EndsWith(s, suffix)) {
131*288bf522SAndroid Build Coastguard Worker         return s.substr(0, s.length() - suffix.length());
132*288bf522SAndroid Build Coastguard Worker     }
133*288bf522SAndroid Build Coastguard Worker     return s;
134*288bf522SAndroid Build Coastguard Worker }
135*288bf522SAndroid Build Coastguard Worker 
136*288bf522SAndroid Build Coastguard Worker // Merge proto with information from metadata.
MergeMetadata(const LpMetadata * metadata,DynamicPartitionsDeviceInfoProto * proto)137*288bf522SAndroid Build Coastguard Worker static bool MergeMetadata(const LpMetadata* metadata,
138*288bf522SAndroid Build Coastguard Worker                           DynamicPartitionsDeviceInfoProto* proto) {
139*288bf522SAndroid Build Coastguard Worker     if (!metadata) return false;
140*288bf522SAndroid Build Coastguard Worker     auto builder = MetadataBuilder::New(*metadata);
141*288bf522SAndroid Build Coastguard Worker     if (!builder) return false;
142*288bf522SAndroid Build Coastguard Worker 
143*288bf522SAndroid Build Coastguard Worker     std::string slot_suffix = GetSlotSuffix();
144*288bf522SAndroid Build Coastguard Worker 
145*288bf522SAndroid Build Coastguard Worker     for (const auto& group_name : builder->ListGroups()) {
146*288bf522SAndroid Build Coastguard Worker         auto group = builder->FindGroup(group_name);
147*288bf522SAndroid Build Coastguard Worker         if (!group) continue;
148*288bf522SAndroid Build Coastguard Worker         if (!base::EndsWith(group_name, slot_suffix)) continue;
149*288bf522SAndroid Build Coastguard Worker         auto group_proto = proto->add_groups();
150*288bf522SAndroid Build Coastguard Worker         group_proto->set_name(RemoveSuffix(group_name, slot_suffix));
151*288bf522SAndroid Build Coastguard Worker         group_proto->set_maximum_size(group->maximum_size());
152*288bf522SAndroid Build Coastguard Worker 
153*288bf522SAndroid Build Coastguard Worker         for (auto partition : builder->ListPartitionsInGroup(group_name)) {
154*288bf522SAndroid Build Coastguard Worker             auto partition_name = partition->name();
155*288bf522SAndroid Build Coastguard Worker             if (!base::EndsWith(partition_name, slot_suffix)) continue;
156*288bf522SAndroid Build Coastguard Worker             auto partition_proto = proto->add_partitions();
157*288bf522SAndroid Build Coastguard Worker             partition_proto->set_name(RemoveSuffix(partition_name, slot_suffix));
158*288bf522SAndroid Build Coastguard Worker             partition_proto->set_group_name(RemoveSuffix(group_name, slot_suffix));
159*288bf522SAndroid Build Coastguard Worker             partition_proto->set_size(partition->size());
160*288bf522SAndroid Build Coastguard Worker             partition_proto->set_is_dynamic(true);
161*288bf522SAndroid Build Coastguard Worker         }
162*288bf522SAndroid Build Coastguard Worker     }
163*288bf522SAndroid Build Coastguard Worker 
164*288bf522SAndroid Build Coastguard Worker     for (const auto& block_device : metadata->block_devices) {
165*288bf522SAndroid Build Coastguard Worker         std::string name = GetBlockDevicePartitionName(block_device);
166*288bf522SAndroid Build Coastguard Worker         BlockDeviceInfo info;
167*288bf522SAndroid Build Coastguard Worker         if (!builder->GetBlockDeviceInfo(name, &info)) {
168*288bf522SAndroid Build Coastguard Worker             continue;
169*288bf522SAndroid Build Coastguard Worker         }
170*288bf522SAndroid Build Coastguard Worker         auto block_device_proto = proto->add_block_devices();
171*288bf522SAndroid Build Coastguard Worker         block_device_proto->set_name(RemoveSuffix(name, slot_suffix));
172*288bf522SAndroid Build Coastguard Worker         block_device_proto->set_size(info.size);
173*288bf522SAndroid Build Coastguard Worker         block_device_proto->set_block_size(info.logical_block_size);
174*288bf522SAndroid Build Coastguard Worker         block_device_proto->set_alignment(info.alignment);
175*288bf522SAndroid Build Coastguard Worker         block_device_proto->set_alignment_offset(info.alignment_offset);
176*288bf522SAndroid Build Coastguard Worker     }
177*288bf522SAndroid Build Coastguard Worker 
178*288bf522SAndroid Build Coastguard Worker     auto super_device_proto = proto->mutable_super_device();
179*288bf522SAndroid Build Coastguard Worker     super_device_proto->set_name(GetSuperPartitionName());
180*288bf522SAndroid Build Coastguard Worker     super_device_proto->set_used_size(builder->UsedSpace());
181*288bf522SAndroid Build Coastguard Worker     super_device_proto->set_total_size(GetTotalSuperPartitionSize(*metadata));
182*288bf522SAndroid Build Coastguard Worker 
183*288bf522SAndroid Build Coastguard Worker     return true;
184*288bf522SAndroid Build Coastguard Worker }
185*288bf522SAndroid Build Coastguard Worker 
186*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
FindPartition(DynamicPartitionsDeviceInfoProto * proto,const std::string & partition)187*288bf522SAndroid Build Coastguard Worker static DynamicPartitionsDeviceInfoProto::Partition* FindPartition(
188*288bf522SAndroid Build Coastguard Worker         DynamicPartitionsDeviceInfoProto* proto, const std::string& partition) {
189*288bf522SAndroid Build Coastguard Worker     for (DynamicPartitionsDeviceInfoProto::Partition& p : *proto->mutable_partitions()) {
190*288bf522SAndroid Build Coastguard Worker         if (p.name() == partition) {
191*288bf522SAndroid Build Coastguard Worker             return &p;
192*288bf522SAndroid Build Coastguard Worker         }
193*288bf522SAndroid Build Coastguard Worker     }
194*288bf522SAndroid Build Coastguard Worker     return nullptr;
195*288bf522SAndroid Build Coastguard Worker }
196*288bf522SAndroid Build Coastguard Worker 
GetReadonlyPartitionName(const android::fs_mgr::FstabEntry & entry)197*288bf522SAndroid Build Coastguard Worker static std::optional<std::string> GetReadonlyPartitionName(const android::fs_mgr::FstabEntry& entry) {
198*288bf522SAndroid Build Coastguard Worker     // Only report readonly partitions.
199*288bf522SAndroid Build Coastguard Worker     if ((entry.flags & MS_RDONLY) == 0) return std::nullopt;
200*288bf522SAndroid Build Coastguard Worker     std::regex regex("/([a-zA-Z_]*)$");
201*288bf522SAndroid Build Coastguard Worker     std::smatch match;
202*288bf522SAndroid Build Coastguard Worker     if (!std::regex_match(entry.mount_point, match, regex)) return std::nullopt;
203*288bf522SAndroid Build Coastguard Worker     // On system-as-root devices, fstab lists / for system partition.
204*288bf522SAndroid Build Coastguard Worker     std::string partition = match[1];
205*288bf522SAndroid Build Coastguard Worker     return partition.empty() ? "system" : partition;
206*288bf522SAndroid Build Coastguard Worker }
207*288bf522SAndroid Build Coastguard Worker 
MergeFsUsage(DynamicPartitionsDeviceInfoProto * proto,std::ostream & cerr)208*288bf522SAndroid Build Coastguard Worker static bool MergeFsUsage(DynamicPartitionsDeviceInfoProto* proto,
209*288bf522SAndroid Build Coastguard Worker                          std::ostream& cerr) {
210*288bf522SAndroid Build Coastguard Worker     using namespace std::string_literals;
211*288bf522SAndroid Build Coastguard Worker     Fstab fstab;
212*288bf522SAndroid Build Coastguard Worker     if (!ReadDefaultFstab(&fstab)) {
213*288bf522SAndroid Build Coastguard Worker         cerr << "Cannot read fstab\n";
214*288bf522SAndroid Build Coastguard Worker         return false;
215*288bf522SAndroid Build Coastguard Worker     }
216*288bf522SAndroid Build Coastguard Worker 
217*288bf522SAndroid Build Coastguard Worker     for (const auto& entry : fstab) {
218*288bf522SAndroid Build Coastguard Worker         auto partition = GetReadonlyPartitionName(entry);
219*288bf522SAndroid Build Coastguard Worker         if (!partition) {
220*288bf522SAndroid Build Coastguard Worker             continue;
221*288bf522SAndroid Build Coastguard Worker         }
222*288bf522SAndroid Build Coastguard Worker 
223*288bf522SAndroid Build Coastguard Worker         // system is mounted to "/";
224*288bf522SAndroid Build Coastguard Worker         const char* mount_point = (entry.mount_point == "/system")
225*288bf522SAndroid Build Coastguard Worker             ? "/" : entry.mount_point.c_str();
226*288bf522SAndroid Build Coastguard Worker 
227*288bf522SAndroid Build Coastguard Worker         struct statvfs vst;
228*288bf522SAndroid Build Coastguard Worker         if (statvfs(mount_point, &vst) == -1) {
229*288bf522SAndroid Build Coastguard Worker             continue;
230*288bf522SAndroid Build Coastguard Worker         }
231*288bf522SAndroid Build Coastguard Worker 
232*288bf522SAndroid Build Coastguard Worker         auto partition_proto = FindPartition(proto, *partition);
233*288bf522SAndroid Build Coastguard Worker         if (partition_proto == nullptr) {
234*288bf522SAndroid Build Coastguard Worker             partition_proto = proto->add_partitions();
235*288bf522SAndroid Build Coastguard Worker             partition_proto->set_name(*partition);
236*288bf522SAndroid Build Coastguard Worker             partition_proto->set_is_dynamic(false);
237*288bf522SAndroid Build Coastguard Worker         }
238*288bf522SAndroid Build Coastguard Worker         partition_proto->set_fs_size((uint64_t)vst.f_blocks * vst.f_frsize);
239*288bf522SAndroid Build Coastguard Worker 
240*288bf522SAndroid Build Coastguard Worker         if (!entry.fs_type.empty()) {
241*288bf522SAndroid Build Coastguard Worker             partition_proto->set_fs_type(entry.fs_type);
242*288bf522SAndroid Build Coastguard Worker         } else {
243*288bf522SAndroid Build Coastguard Worker             partition_proto->set_fs_type("UNKNOWN");
244*288bf522SAndroid Build Coastguard Worker         }
245*288bf522SAndroid Build Coastguard Worker 
246*288bf522SAndroid Build Coastguard Worker         if (vst.f_bavail <= vst.f_blocks) {
247*288bf522SAndroid Build Coastguard Worker             partition_proto->set_fs_used((uint64_t)(vst.f_blocks - vst.f_bavail) * vst.f_frsize);
248*288bf522SAndroid Build Coastguard Worker         }
249*288bf522SAndroid Build Coastguard Worker     }
250*288bf522SAndroid Build Coastguard Worker     return true;
251*288bf522SAndroid Build Coastguard Worker }
DumpSnapshotState(std::ostream & output)252*288bf522SAndroid Build Coastguard Worker static void DumpSnapshotState(std::ostream& output) {
253*288bf522SAndroid Build Coastguard Worker     if (android::base::GetBoolProperty("ro.virtual_ab.enabled", false)) {
254*288bf522SAndroid Build Coastguard Worker         if (auto sm = android::snapshot::SnapshotManager::New()) {
255*288bf522SAndroid Build Coastguard Worker             output << "---------------\n";
256*288bf522SAndroid Build Coastguard Worker             output << "Snapshot state:\n";
257*288bf522SAndroid Build Coastguard Worker             output << "---------------\n";
258*288bf522SAndroid Build Coastguard Worker             sm->Dump(output);
259*288bf522SAndroid Build Coastguard Worker         }
260*288bf522SAndroid Build Coastguard Worker     }
261*288bf522SAndroid Build Coastguard Worker }
262*288bf522SAndroid Build Coastguard Worker #endif
263*288bf522SAndroid Build Coastguard Worker 
264*288bf522SAndroid Build Coastguard Worker // Print output in JSON format.
265*288bf522SAndroid Build Coastguard Worker // If successful, this function must write a valid JSON string to "cout" and return 0.
PrintJson(const LpMetadata * metadata,std::ostream & cout,std::ostream & cerr)266*288bf522SAndroid Build Coastguard Worker static int PrintJson(const LpMetadata* metadata, std::ostream& cout,
267*288bf522SAndroid Build Coastguard Worker                      std::ostream& cerr) {
268*288bf522SAndroid Build Coastguard Worker     DynamicPartitionsDeviceInfoProto proto;
269*288bf522SAndroid Build Coastguard Worker 
270*288bf522SAndroid Build Coastguard Worker     if (base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
271*288bf522SAndroid Build Coastguard Worker         proto.set_enabled(true);
272*288bf522SAndroid Build Coastguard Worker     }
273*288bf522SAndroid Build Coastguard Worker 
274*288bf522SAndroid Build Coastguard Worker     if (base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false)) {
275*288bf522SAndroid Build Coastguard Worker         proto.set_retrofit(true);
276*288bf522SAndroid Build Coastguard Worker     }
277*288bf522SAndroid Build Coastguard Worker 
278*288bf522SAndroid Build Coastguard Worker     if (!MergeMetadata(metadata, &proto)) {
279*288bf522SAndroid Build Coastguard Worker         cerr << "Warning: Failed to read metadata.\n";
280*288bf522SAndroid Build Coastguard Worker     }
281*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
282*288bf522SAndroid Build Coastguard Worker     if (!MergeFsUsage(&proto, cerr)) {
283*288bf522SAndroid Build Coastguard Worker         cerr << "Warning: Failed to read filesystem size and usage.\n";
284*288bf522SAndroid Build Coastguard Worker     }
285*288bf522SAndroid Build Coastguard Worker #endif
286*288bf522SAndroid Build Coastguard Worker 
287*288bf522SAndroid Build Coastguard Worker     auto error_or_json = jsonpb::MessageToJsonString(proto);
288*288bf522SAndroid Build Coastguard Worker     if (!error_or_json.ok()) {
289*288bf522SAndroid Build Coastguard Worker         cerr << error_or_json.error() << "\n";
290*288bf522SAndroid Build Coastguard Worker         return EX_SOFTWARE;
291*288bf522SAndroid Build Coastguard Worker     }
292*288bf522SAndroid Build Coastguard Worker     cout << *error_or_json;
293*288bf522SAndroid Build Coastguard Worker     return EX_OK;
294*288bf522SAndroid Build Coastguard Worker }
295*288bf522SAndroid Build Coastguard Worker 
DumpMetadataSize(const LpMetadata & metadata,std::ostream & cout)296*288bf522SAndroid Build Coastguard Worker static int DumpMetadataSize(const LpMetadata& metadata, std::ostream& cout) {
297*288bf522SAndroid Build Coastguard Worker     auto super_device = GetMetadataSuperBlockDevice(metadata);
298*288bf522SAndroid Build Coastguard Worker     uint64_t metadata_size = super_device->first_logical_sector * LP_SECTOR_SIZE;
299*288bf522SAndroid Build Coastguard Worker     cout << metadata_size << std::endl;
300*288bf522SAndroid Build Coastguard Worker     return EX_OK;
301*288bf522SAndroid Build Coastguard Worker }
302*288bf522SAndroid Build Coastguard Worker 
303*288bf522SAndroid Build Coastguard Worker class FileOrBlockDeviceOpener final : public PartitionOpener {
304*288bf522SAndroid Build Coastguard Worker public:
Open(const std::string & path,int flags) const305*288bf522SAndroid Build Coastguard Worker     android::base::unique_fd Open(const std::string& path, int flags) const override {
306*288bf522SAndroid Build Coastguard Worker         // Try a local file first.
307*288bf522SAndroid Build Coastguard Worker         android::base::unique_fd fd;
308*288bf522SAndroid Build Coastguard Worker 
309*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
310*288bf522SAndroid Build Coastguard Worker         fd.reset(android_get_control_file(path.c_str()));
311*288bf522SAndroid Build Coastguard Worker         if (fd >= 0) return fd;
312*288bf522SAndroid Build Coastguard Worker #endif
313*288bf522SAndroid Build Coastguard Worker         fd.reset(open(path.c_str(), flags));
314*288bf522SAndroid Build Coastguard Worker         if (fd >= 0) return fd;
315*288bf522SAndroid Build Coastguard Worker 
316*288bf522SAndroid Build Coastguard Worker         return PartitionOpener::Open(path, flags);
317*288bf522SAndroid Build Coastguard Worker     }
318*288bf522SAndroid Build Coastguard Worker };
319*288bf522SAndroid Build Coastguard Worker 
320*288bf522SAndroid Build Coastguard Worker std::optional<std::tuple<std::string, uint64_t>>
ParseLinearExtentData(const LpMetadata & pt,const LpMetadataExtent & extent)321*288bf522SAndroid Build Coastguard Worker ParseLinearExtentData(const LpMetadata& pt, const LpMetadataExtent& extent) {
322*288bf522SAndroid Build Coastguard Worker     if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
323*288bf522SAndroid Build Coastguard Worker         return std::nullopt;
324*288bf522SAndroid Build Coastguard Worker     }
325*288bf522SAndroid Build Coastguard Worker     const auto& block_device = pt.block_devices[extent.target_source];
326*288bf522SAndroid Build Coastguard Worker     std::string device_name = GetBlockDevicePartitionName(block_device);
327*288bf522SAndroid Build Coastguard Worker     return std::make_tuple(std::move(device_name), extent.target_data);
328*288bf522SAndroid Build Coastguard Worker }
329*288bf522SAndroid Build Coastguard Worker 
PrintMetadata(const LpMetadata & pt,std::ostream & cout)330*288bf522SAndroid Build Coastguard Worker static void PrintMetadata(const LpMetadata& pt, std::ostream& cout) {
331*288bf522SAndroid Build Coastguard Worker     cout << "Metadata version: " << pt.header.major_version << "." << pt.header.minor_version
332*288bf522SAndroid Build Coastguard Worker          << "\n";
333*288bf522SAndroid Build Coastguard Worker     cout << "Metadata size: " << (pt.header.header_size + pt.header.tables_size) << " bytes\n";
334*288bf522SAndroid Build Coastguard Worker     cout << "Metadata max size: " << pt.geometry.metadata_max_size << " bytes\n";
335*288bf522SAndroid Build Coastguard Worker     cout << "Metadata slot count: " << pt.geometry.metadata_slot_count << "\n";
336*288bf522SAndroid Build Coastguard Worker     cout << "Header flags: " << BuildHeaderFlagString(pt.header.flags) << "\n";
337*288bf522SAndroid Build Coastguard Worker     cout << "Partition table:\n";
338*288bf522SAndroid Build Coastguard Worker     cout << "------------------------\n";
339*288bf522SAndroid Build Coastguard Worker 
340*288bf522SAndroid Build Coastguard Worker     std::vector<std::tuple<std::string, const LpMetadataExtent*>> extents;
341*288bf522SAndroid Build Coastguard Worker 
342*288bf522SAndroid Build Coastguard Worker     for (const auto& partition : pt.partitions) {
343*288bf522SAndroid Build Coastguard Worker         std::string name = GetPartitionName(partition);
344*288bf522SAndroid Build Coastguard Worker         std::string group_name = GetPartitionGroupName(pt.groups[partition.group_index]);
345*288bf522SAndroid Build Coastguard Worker         cout << "  Name: " << name << "\n";
346*288bf522SAndroid Build Coastguard Worker         cout << "  Group: " << group_name << "\n";
347*288bf522SAndroid Build Coastguard Worker         cout << "  Attributes: " << BuildAttributeString(partition.attributes) << "\n";
348*288bf522SAndroid Build Coastguard Worker         cout << "  Extents:\n";
349*288bf522SAndroid Build Coastguard Worker         uint64_t first_sector = 0;
350*288bf522SAndroid Build Coastguard Worker         for (size_t i = 0; i < partition.num_extents; i++) {
351*288bf522SAndroid Build Coastguard Worker             const LpMetadataExtent& extent = pt.extents[partition.first_extent_index + i];
352*288bf522SAndroid Build Coastguard Worker             cout << "    " << first_sector << " .. " << (first_sector + extent.num_sectors - 1)
353*288bf522SAndroid Build Coastguard Worker                  << " ";
354*288bf522SAndroid Build Coastguard Worker             first_sector += extent.num_sectors;
355*288bf522SAndroid Build Coastguard Worker             if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
356*288bf522SAndroid Build Coastguard Worker                 const auto& block_device = pt.block_devices[extent.target_source];
357*288bf522SAndroid Build Coastguard Worker                 std::string device_name = GetBlockDevicePartitionName(block_device);
358*288bf522SAndroid Build Coastguard Worker                 cout << "linear " << device_name.c_str() << " " << extent.target_data;
359*288bf522SAndroid Build Coastguard Worker             } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
360*288bf522SAndroid Build Coastguard Worker                 cout << "zero";
361*288bf522SAndroid Build Coastguard Worker             }
362*288bf522SAndroid Build Coastguard Worker             extents.push_back(std::make_tuple(name, &extent));
363*288bf522SAndroid Build Coastguard Worker             cout << "\n";
364*288bf522SAndroid Build Coastguard Worker         }
365*288bf522SAndroid Build Coastguard Worker         cout << "------------------------\n";
366*288bf522SAndroid Build Coastguard Worker     }
367*288bf522SAndroid Build Coastguard Worker 
368*288bf522SAndroid Build Coastguard Worker     std::sort(extents.begin(), extents.end(), [&](const auto& x, const auto& y) {
369*288bf522SAndroid Build Coastguard Worker         auto x_data = ParseLinearExtentData(pt, *std::get<1>(x));
370*288bf522SAndroid Build Coastguard Worker         auto y_data = ParseLinearExtentData(pt, *std::get<1>(y));
371*288bf522SAndroid Build Coastguard Worker         return x_data < y_data;
372*288bf522SAndroid Build Coastguard Worker     });
373*288bf522SAndroid Build Coastguard Worker 
374*288bf522SAndroid Build Coastguard Worker     cout << "Super partition layout:\n";
375*288bf522SAndroid Build Coastguard Worker     cout << "------------------------\n";
376*288bf522SAndroid Build Coastguard Worker     for (auto&& [name, extent] : extents) {
377*288bf522SAndroid Build Coastguard Worker         auto data = ParseLinearExtentData(pt, *extent);
378*288bf522SAndroid Build Coastguard Worker         if (!data) continue;
379*288bf522SAndroid Build Coastguard Worker         auto&& [block_device, offset] = *data;
380*288bf522SAndroid Build Coastguard Worker         cout << block_device << ": " << offset << " .. " << (offset + extent->num_sectors)
381*288bf522SAndroid Build Coastguard Worker              << ": " << name << " (" << extent->num_sectors << " sectors)\n";
382*288bf522SAndroid Build Coastguard Worker     }
383*288bf522SAndroid Build Coastguard Worker     cout << "------------------------\n";
384*288bf522SAndroid Build Coastguard Worker 
385*288bf522SAndroid Build Coastguard Worker     cout << "Block device table:\n";
386*288bf522SAndroid Build Coastguard Worker     cout << "------------------------\n";
387*288bf522SAndroid Build Coastguard Worker     for (const auto& block_device : pt.block_devices) {
388*288bf522SAndroid Build Coastguard Worker         std::string partition_name = GetBlockDevicePartitionName(block_device);
389*288bf522SAndroid Build Coastguard Worker         cout << "  Partition name: " << partition_name << "\n";
390*288bf522SAndroid Build Coastguard Worker         cout << "  First sector: " << block_device.first_logical_sector << "\n";
391*288bf522SAndroid Build Coastguard Worker         cout << "  Size: " << block_device.size << " bytes\n";
392*288bf522SAndroid Build Coastguard Worker         cout << "  Flags: " << BuildBlockDeviceFlagString(block_device.flags) << "\n";
393*288bf522SAndroid Build Coastguard Worker         cout << "------------------------\n";
394*288bf522SAndroid Build Coastguard Worker     }
395*288bf522SAndroid Build Coastguard Worker 
396*288bf522SAndroid Build Coastguard Worker     cout << "Group table:\n";
397*288bf522SAndroid Build Coastguard Worker     cout << "------------------------\n";
398*288bf522SAndroid Build Coastguard Worker     for (const auto& group : pt.groups) {
399*288bf522SAndroid Build Coastguard Worker         std::string group_name = GetPartitionGroupName(group);
400*288bf522SAndroid Build Coastguard Worker         cout << "  Name: " << group_name << "\n";
401*288bf522SAndroid Build Coastguard Worker         cout << "  Maximum size: " << group.maximum_size << " bytes\n";
402*288bf522SAndroid Build Coastguard Worker         cout << "  Flags: " << BuildGroupFlagString(group.flags) << "\n";
403*288bf522SAndroid Build Coastguard Worker         cout << "------------------------\n";
404*288bf522SAndroid Build Coastguard Worker     }
405*288bf522SAndroid Build Coastguard Worker }
406*288bf522SAndroid Build Coastguard Worker 
ReadDeviceOrFile(const std::string & path,uint32_t slot)407*288bf522SAndroid Build Coastguard Worker static std::unique_ptr<LpMetadata> ReadDeviceOrFile(const std::string& path, uint32_t slot) {
408*288bf522SAndroid Build Coastguard Worker     if (IsEmptySuperImage(path)) {
409*288bf522SAndroid Build Coastguard Worker         return ReadFromImageFile(path);
410*288bf522SAndroid Build Coastguard Worker     }
411*288bf522SAndroid Build Coastguard Worker     return ReadMetadata(path, slot);
412*288bf522SAndroid Build Coastguard Worker }
413*288bf522SAndroid Build Coastguard Worker 
LpdumpMain(int argc,char * argv[],std::ostream & cout,std::ostream & cerr)414*288bf522SAndroid Build Coastguard Worker int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) {
415*288bf522SAndroid Build Coastguard Worker     // clang-format off
416*288bf522SAndroid Build Coastguard Worker     struct option options[] = {
417*288bf522SAndroid Build Coastguard Worker         { "all", no_argument, nullptr, 'a' },
418*288bf522SAndroid Build Coastguard Worker         { "slot", required_argument, nullptr, 's' },
419*288bf522SAndroid Build Coastguard Worker         { "help", no_argument, nullptr, 'h' },
420*288bf522SAndroid Build Coastguard Worker         { "json", no_argument, nullptr, 'j' },
421*288bf522SAndroid Build Coastguard Worker         { "dump-metadata-size", no_argument, nullptr, 'd' },
422*288bf522SAndroid Build Coastguard Worker         { "is-super-empty", no_argument, nullptr, 'e' },
423*288bf522SAndroid Build Coastguard Worker         { nullptr, 0, nullptr, 0 },
424*288bf522SAndroid Build Coastguard Worker     };
425*288bf522SAndroid Build Coastguard Worker     // clang-format on
426*288bf522SAndroid Build Coastguard Worker 
427*288bf522SAndroid Build Coastguard Worker     // Allow this function to be invoked by lpdumpd multiple times.
428*288bf522SAndroid Build Coastguard Worker     optind = 1;
429*288bf522SAndroid Build Coastguard Worker 
430*288bf522SAndroid Build Coastguard Worker     int rv;
431*288bf522SAndroid Build Coastguard Worker     int index;
432*288bf522SAndroid Build Coastguard Worker     bool json = false;
433*288bf522SAndroid Build Coastguard Worker     bool dump_metadata_size = false;
434*288bf522SAndroid Build Coastguard Worker     bool dump_all = false;
435*288bf522SAndroid Build Coastguard Worker     std::optional<uint32_t> slot;
436*288bf522SAndroid Build Coastguard Worker     while ((rv = getopt_long_only(argc, argv, "s:jhde", options, &index)) != -1) {
437*288bf522SAndroid Build Coastguard Worker         switch (rv) {
438*288bf522SAndroid Build Coastguard Worker             case 'a':
439*288bf522SAndroid Build Coastguard Worker                 dump_all = true;
440*288bf522SAndroid Build Coastguard Worker                 break;
441*288bf522SAndroid Build Coastguard Worker             case 'h':
442*288bf522SAndroid Build Coastguard Worker                 usage(argc, argv, cout);
443*288bf522SAndroid Build Coastguard Worker                 return EX_OK;
444*288bf522SAndroid Build Coastguard Worker             case 's': {
445*288bf522SAndroid Build Coastguard Worker                 uint32_t slot_arg;
446*288bf522SAndroid Build Coastguard Worker                 if (android::base::ParseUint(optarg, &slot_arg)) {
447*288bf522SAndroid Build Coastguard Worker                     slot = slot_arg;
448*288bf522SAndroid Build Coastguard Worker                 } else {
449*288bf522SAndroid Build Coastguard Worker                     slot = SlotNumberForSlotSuffix(optarg);
450*288bf522SAndroid Build Coastguard Worker                 }
451*288bf522SAndroid Build Coastguard Worker                 break;
452*288bf522SAndroid Build Coastguard Worker             }
453*288bf522SAndroid Build Coastguard Worker             case 'e':
454*288bf522SAndroid Build Coastguard Worker                 // This is ignored, we now derive whether it's empty automatically.
455*288bf522SAndroid Build Coastguard Worker                 break;
456*288bf522SAndroid Build Coastguard Worker             case 'd':
457*288bf522SAndroid Build Coastguard Worker                 dump_metadata_size = true;
458*288bf522SAndroid Build Coastguard Worker                 break;
459*288bf522SAndroid Build Coastguard Worker             case 'j':
460*288bf522SAndroid Build Coastguard Worker                 json = true;
461*288bf522SAndroid Build Coastguard Worker                 break;
462*288bf522SAndroid Build Coastguard Worker             case '?':
463*288bf522SAndroid Build Coastguard Worker             case ':':
464*288bf522SAndroid Build Coastguard Worker                 return usage(argc, argv, cerr);
465*288bf522SAndroid Build Coastguard Worker         }
466*288bf522SAndroid Build Coastguard Worker     }
467*288bf522SAndroid Build Coastguard Worker 
468*288bf522SAndroid Build Coastguard Worker     if (dump_all) {
469*288bf522SAndroid Build Coastguard Worker         if (slot.has_value()) {
470*288bf522SAndroid Build Coastguard Worker             cerr << "Cannot specify both --all and --slot.\n";
471*288bf522SAndroid Build Coastguard Worker             return usage(argc, argv, cerr);
472*288bf522SAndroid Build Coastguard Worker         }
473*288bf522SAndroid Build Coastguard Worker         if (json) {
474*288bf522SAndroid Build Coastguard Worker             cerr << "Cannot specify both --all and --json.\n";
475*288bf522SAndroid Build Coastguard Worker             return usage(argc, argv, cerr);
476*288bf522SAndroid Build Coastguard Worker         }
477*288bf522SAndroid Build Coastguard Worker 
478*288bf522SAndroid Build Coastguard Worker         // When dumping everything always start from the first slot.
479*288bf522SAndroid Build Coastguard Worker         slot = 0;
480*288bf522SAndroid Build Coastguard Worker     }
481*288bf522SAndroid Build Coastguard Worker 
482*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
483*288bf522SAndroid Build Coastguard Worker     // Use the current slot as a default for A/B devices.
484*288bf522SAndroid Build Coastguard Worker     auto current_slot_suffix = GetSlotSuffix();
485*288bf522SAndroid Build Coastguard Worker     if (!slot.has_value() && !current_slot_suffix.empty()) {
486*288bf522SAndroid Build Coastguard Worker         slot = SlotNumberForSlotSuffix(current_slot_suffix);
487*288bf522SAndroid Build Coastguard Worker     }
488*288bf522SAndroid Build Coastguard Worker #endif
489*288bf522SAndroid Build Coastguard Worker 
490*288bf522SAndroid Build Coastguard Worker     // If we still haven't determined a slot yet, use the first one.
491*288bf522SAndroid Build Coastguard Worker     if (!slot.has_value()) {
492*288bf522SAndroid Build Coastguard Worker         slot = 0;
493*288bf522SAndroid Build Coastguard Worker     }
494*288bf522SAndroid Build Coastguard Worker 
495*288bf522SAndroid Build Coastguard Worker     // Determine the path to the super partition (or image). If an explicit
496*288bf522SAndroid Build Coastguard Worker     // path is given, we use it for everything. Otherwise, we will infer it
497*288bf522SAndroid Build Coastguard Worker     // at the time we need to read metadata.
498*288bf522SAndroid Build Coastguard Worker     std::string super_path;
499*288bf522SAndroid Build Coastguard Worker     bool override_super_name = (optind < argc);
500*288bf522SAndroid Build Coastguard Worker     if (override_super_name) {
501*288bf522SAndroid Build Coastguard Worker         super_path = argv[optind++];
502*288bf522SAndroid Build Coastguard Worker     } else {
503*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
504*288bf522SAndroid Build Coastguard Worker         super_path = GetSuperPartitionName(slot);
505*288bf522SAndroid Build Coastguard Worker #else
506*288bf522SAndroid Build Coastguard Worker         cerr << "Must specify a super partition image.\n";
507*288bf522SAndroid Build Coastguard Worker         return usage(argc, argv, cerr);
508*288bf522SAndroid Build Coastguard Worker #endif
509*288bf522SAndroid Build Coastguard Worker     }
510*288bf522SAndroid Build Coastguard Worker 
511*288bf522SAndroid Build Coastguard Worker     auto pt = ReadDeviceOrFile(super_path, slot.value());
512*288bf522SAndroid Build Coastguard Worker 
513*288bf522SAndroid Build Coastguard Worker     // --json option doesn't require metadata to be present.
514*288bf522SAndroid Build Coastguard Worker     if (json) {
515*288bf522SAndroid Build Coastguard Worker         return PrintJson(pt.get(), cout, cerr);
516*288bf522SAndroid Build Coastguard Worker     }
517*288bf522SAndroid Build Coastguard Worker 
518*288bf522SAndroid Build Coastguard Worker     if (!pt) {
519*288bf522SAndroid Build Coastguard Worker         cerr << "Failed to read metadata.\n";
520*288bf522SAndroid Build Coastguard Worker         return EX_NOINPUT;
521*288bf522SAndroid Build Coastguard Worker     }
522*288bf522SAndroid Build Coastguard Worker 
523*288bf522SAndroid Build Coastguard Worker     if (dump_metadata_size) {
524*288bf522SAndroid Build Coastguard Worker         return DumpMetadataSize(*pt.get(), cout);
525*288bf522SAndroid Build Coastguard Worker     }
526*288bf522SAndroid Build Coastguard Worker 
527*288bf522SAndroid Build Coastguard Worker     // When running on the device, we can check the slot count. Otherwise we
528*288bf522SAndroid Build Coastguard Worker     // use the # of metadata slots. (There is an extra slot we don't want to
529*288bf522SAndroid Build Coastguard Worker     // dump because it is currently unused.)
530*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
531*288bf522SAndroid Build Coastguard Worker     uint32_t num_slots = current_slot_suffix.empty() ? 1 : 2;
532*288bf522SAndroid Build Coastguard Worker     if (dump_all && num_slots > 1) {
533*288bf522SAndroid Build Coastguard Worker         cout << "Current slot: " << current_slot_suffix << "\n";
534*288bf522SAndroid Build Coastguard Worker     }
535*288bf522SAndroid Build Coastguard Worker #else
536*288bf522SAndroid Build Coastguard Worker     uint32_t num_slots = pt->geometry.metadata_slot_count;
537*288bf522SAndroid Build Coastguard Worker #endif
538*288bf522SAndroid Build Coastguard Worker     // Empty images only have one slot.
539*288bf522SAndroid Build Coastguard Worker     if (IsEmptySuperImage(super_path)) {
540*288bf522SAndroid Build Coastguard Worker         num_slots = 1;
541*288bf522SAndroid Build Coastguard Worker     }
542*288bf522SAndroid Build Coastguard Worker 
543*288bf522SAndroid Build Coastguard Worker     if (num_slots > 1) {
544*288bf522SAndroid Build Coastguard Worker         cout << "Slot " << slot.value() << ":\n";
545*288bf522SAndroid Build Coastguard Worker     }
546*288bf522SAndroid Build Coastguard Worker     PrintMetadata(*pt.get(), cout);
547*288bf522SAndroid Build Coastguard Worker 
548*288bf522SAndroid Build Coastguard Worker     if (dump_all) {
549*288bf522SAndroid Build Coastguard Worker         for (uint32_t i = 1; i < num_slots; i++) {
550*288bf522SAndroid Build Coastguard Worker             if (!override_super_name) {
551*288bf522SAndroid Build Coastguard Worker                 super_path = GetSuperPartitionName(i);
552*288bf522SAndroid Build Coastguard Worker             }
553*288bf522SAndroid Build Coastguard Worker 
554*288bf522SAndroid Build Coastguard Worker             pt = ReadDeviceOrFile(super_path, i);
555*288bf522SAndroid Build Coastguard Worker             if (!pt) {
556*288bf522SAndroid Build Coastguard Worker                 continue;
557*288bf522SAndroid Build Coastguard Worker             }
558*288bf522SAndroid Build Coastguard Worker 
559*288bf522SAndroid Build Coastguard Worker             cout << "\nSlot " << i << ":\n";
560*288bf522SAndroid Build Coastguard Worker             PrintMetadata(*pt.get(), cout);
561*288bf522SAndroid Build Coastguard Worker         }
562*288bf522SAndroid Build Coastguard Worker     }
563*288bf522SAndroid Build Coastguard Worker #ifdef __ANDROID__
564*288bf522SAndroid Build Coastguard Worker     DumpSnapshotState(cout);
565*288bf522SAndroid Build Coastguard Worker #endif
566*288bf522SAndroid Build Coastguard Worker 
567*288bf522SAndroid Build Coastguard Worker     return EX_OK;
568*288bf522SAndroid Build Coastguard Worker }
569*288bf522SAndroid Build Coastguard Worker 
LpdumpMain(int argc,char * argv[])570*288bf522SAndroid Build Coastguard Worker int LpdumpMain(int argc, char* argv[]) {
571*288bf522SAndroid Build Coastguard Worker     return LpdumpMain(argc, argv, std::cout, std::cerr);
572*288bf522SAndroid Build Coastguard Worker }
573