blob: 9768294068f08e33eb09f7068bcbd10b0537763e [file] [log] [blame]
David Anderson41241232018-06-13 16:50:11 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <getopt.h>
18#include <inttypes.h>
Yifan Hong7ea1a932019-03-15 16:06:50 -070019#include <sys/mount.h>
David Anderson41241232018-06-13 16:50:11 -070020#include <sys/stat.h>
Yifan Hong7ea1a932019-03-15 16:06:50 -070021#include <sys/statvfs.h>
David Anderson41241232018-06-13 16:50:11 -070022#include <sys/types.h>
23#include <sysexits.h>
24#include <unistd.h>
25
Yifan Hong6ba2d0c2019-09-23 18:01:20 -070026#include <algorithm>
Yifan Hongb48d79f2019-03-19 16:18:11 -070027#include <iostream>
Yifan Hong7ea1a932019-03-15 16:06:50 -070028#include <optional>
29#include <regex>
David Anderson41241232018-06-13 16:50:11 -070030#include <string>
David Anderson1c5907a2018-11-07 18:27:14 -080031#include <vector>
David Anderson41241232018-06-13 16:50:11 -070032
33#include <android-base/parseint.h>
Yifan Hong7ea1a932019-03-15 16:06:50 -070034#include <android-base/properties.h>
35#include <android-base/strings.h>
David Anderson299abc72018-12-12 13:36:43 -080036#ifdef __ANDROID__
Yifan Hongb84fb572019-03-15 14:19:08 -070037#include <cutils/android_get_control_file.h>
David Anderson299abc72018-12-12 13:36:43 -080038#include <fs_mgr.h>
39#endif
Yifan Hong7ea1a932019-03-15 16:06:50 -070040#include <jsonpb/jsonpb.h>
41#include <liblp/builder.h>
David Anderson0640c672018-07-12 13:10:57 -070042#include <liblp/liblp.h>
David Anderson41241232018-06-13 16:50:11 -070043
Yifan Hong7ea1a932019-03-15 16:06:50 -070044#include "dynamic_partitions_device_info.pb.h"
David Anderson41241232018-06-13 16:50:11 -070045using namespace android;
46using namespace android::fs_mgr;
47
Yifan Hongb48d79f2019-03-19 16:18:11 -070048static int usage(int /* argc */, char* argv[], std::ostream& cerr) {
49 cerr << argv[0]
50 << " - command-line tool for dumping Android Logical Partition images.\n"
David Anderson41241232018-06-13 16:50:11 -070051 "\n"
52 "Usage:\n"
Yifan Hongb48d79f2019-03-19 16:18:11 -070053 " "
54 << argv[0]
Yifan Hong7ea1a932019-03-15 16:06:50 -070055 << " [-s <SLOT#>|--slot=<SLOT#>] [-j|--json] [FILE|DEVICE]\n"
David Anderson41241232018-06-13 16:50:11 -070056 "\n"
57 "Options:\n"
Yifan Hong7ea1a932019-03-15 16:06:50 -070058 " -s, --slot=N Slot number or suffix.\n"
David Anderson289570e2019-05-22 14:31:06 -070059 " -j, --json Print in JSON format.\n"
David Anderson289570e2019-05-22 14:31:06 -070060 " -d, --dump-metadata-size\n"
61 " Print the space reserved for metadata to stdout\n"
David Andersoncd5227d2019-09-05 18:31:12 -070062 " in bytes.\n"
63 " -a, --all Dump all slots (not available in JSON mode).\n";
David Anderson41241232018-06-13 16:50:11 -070064 return EX_USAGE;
65}
66
David Andersonbdcadc72018-11-16 21:38:40 -080067static std::string BuildFlagString(const std::vector<std::string>& strings) {
68 return strings.empty() ? "none" : android::base::Join(strings, ",");
69}
70
David Andersonab1b0952019-12-12 17:12:27 -080071static std::string BuildHeaderFlagString(uint32_t flags) {
72 std::vector<std::string> strings;
73
David Anderson7b14a8d2019-12-13 15:34:54 -080074 if (flags & LP_HEADER_FLAG_VIRTUAL_AB_DEVICE) {
75 strings.emplace_back("virtual_ab_device");
76 flags &= ~LP_HEADER_FLAG_VIRTUAL_AB_DEVICE;
77 }
78
David Andersonab1b0952019-12-12 17:12:27 -080079 for (uint32_t i = 0; i < sizeof(flags) * 8; i++) {
Greg Kaiser669932f2019-12-17 05:43:47 -080080 if (!(flags & (1U << i))) {
David Andersonab1b0952019-12-12 17:12:27 -080081 continue;
82 }
83 strings.emplace_back("unknown_flag_bit_" + std::to_string(i));
84 }
85 return BuildFlagString(strings);
86}
87
David Anderson41241232018-06-13 16:50:11 -070088static std::string BuildAttributeString(uint32_t attrs) {
David Anderson1c5907a2018-11-07 18:27:14 -080089 std::vector<std::string> strings;
90 if (attrs & LP_PARTITION_ATTR_READONLY) strings.emplace_back("readonly");
91 if (attrs & LP_PARTITION_ATTR_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
David Anderson817cab02019-08-27 13:44:48 -070092 if (attrs & LP_PARTITION_ATTR_UPDATED) strings.emplace_back("updated");
David Anderson8ac2c112019-12-18 15:11:45 -080093 if (attrs & LP_PARTITION_ATTR_DISABLED) strings.emplace_back("disabled");
David Andersonbdcadc72018-11-16 21:38:40 -080094 return BuildFlagString(strings);
95}
96
97static std::string BuildGroupFlagString(uint32_t flags) {
98 std::vector<std::string> strings;
99 if (flags & LP_GROUP_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
100 return BuildFlagString(strings);
101}
102
103static std::string BuildBlockDeviceFlagString(uint32_t flags) {
104 std::vector<std::string> strings;
105 if (flags & LP_BLOCK_DEVICE_SLOT_SUFFIXED) strings.emplace_back("slot-suffixed");
106 return BuildFlagString(strings);
David Anderson41241232018-06-13 16:50:11 -0700107}
108
Yifan Hongb84fb572019-03-15 14:19:08 -0700109// Reimplementation of fs_mgr_get_slot_suffix() without reading
110// kernel commandline.
111static std::string GetSlotSuffix() {
112 return base::GetProperty("ro.boot.slot_suffix", "");
113}
114
115// Reimplementation of fs_mgr_get_super_partition_name() without reading
116// kernel commandline. Always return the super partition at current slot.
David Anderson998892b2019-09-05 18:53:21 -0700117static std::string GetSuperPartitionName(const std::optional<uint32_t>& slot = {}) {
Yifan Hongb84fb572019-03-15 14:19:08 -0700118 std::string super_partition = base::GetProperty("ro.boot.super_partition", "");
119 if (super_partition.empty()) {
120 return LP_METADATA_DEFAULT_PARTITION_NAME;
121 }
David Anderson998892b2019-09-05 18:53:21 -0700122 if (slot.has_value()) {
123 return super_partition + SlotSuffixForSlotNumber(slot.value());
124 }
Yifan Hongb84fb572019-03-15 14:19:08 -0700125 return super_partition + GetSlotSuffix();
126}
127
Yifan Hong7ea1a932019-03-15 16:06:50 -0700128static std::string RemoveSuffix(const std::string& s, const std::string& suffix) {
129 if (base::EndsWith(s, suffix)) {
130 return s.substr(0, s.length() - suffix.length());
131 }
132 return s;
133}
134
135// Merge proto with information from metadata.
136static bool MergeMetadata(const LpMetadata* metadata,
137 DynamicPartitionsDeviceInfoProto* proto) {
138 if (!metadata) return false;
139 auto builder = MetadataBuilder::New(*metadata);
140 if (!builder) return false;
141
142 std::string slot_suffix = GetSlotSuffix();
143
144 for (const auto& group_name : builder->ListGroups()) {
145 auto group = builder->FindGroup(group_name);
146 if (!group) continue;
147 if (!base::EndsWith(group_name, slot_suffix)) continue;
148 auto group_proto = proto->add_groups();
149 group_proto->set_name(RemoveSuffix(group_name, slot_suffix));
150 group_proto->set_maximum_size(group->maximum_size());
151
152 for (auto partition : builder->ListPartitionsInGroup(group_name)) {
153 auto partition_name = partition->name();
154 if (!base::EndsWith(partition_name, slot_suffix)) continue;
155 auto partition_proto = proto->add_partitions();
156 partition_proto->set_name(RemoveSuffix(partition_name, slot_suffix));
157 partition_proto->set_group_name(RemoveSuffix(group_name, slot_suffix));
158 partition_proto->set_size(partition->size());
159 partition_proto->set_is_dynamic(true);
160 }
161 }
162
163 for (const auto& block_device : metadata->block_devices) {
164 std::string name = GetBlockDevicePartitionName(block_device);
165 BlockDeviceInfo info;
166 if (!builder->GetBlockDeviceInfo(name, &info)) {
167 continue;
168 }
169 auto block_device_proto = proto->add_block_devices();
170 block_device_proto->set_name(RemoveSuffix(name, slot_suffix));
171 block_device_proto->set_size(info.size);
172 block_device_proto->set_block_size(info.logical_block_size);
173 block_device_proto->set_alignment(info.alignment);
174 block_device_proto->set_alignment_offset(info.alignment_offset);
175 }
176 return true;
177}
178
179#ifdef __ANDROID__
180static DynamicPartitionsDeviceInfoProto::Partition* FindPartition(
181 DynamicPartitionsDeviceInfoProto* proto, const std::string& partition) {
182 for (DynamicPartitionsDeviceInfoProto::Partition& p : *proto->mutable_partitions()) {
183 if (p.name() == partition) {
184 return &p;
185 }
186 }
187 return nullptr;
188}
189
190static std::optional<std::string> GetReadonlyPartitionName(const android::fs_mgr::FstabEntry& entry) {
191 // Only report readonly partitions.
192 if ((entry.flags & MS_RDONLY) == 0) return std::nullopt;
193 std::regex regex("/([a-zA-Z_]*)$");
194 std::smatch match;
195 if (!std::regex_match(entry.mount_point, match, regex)) return std::nullopt;
196 // On system-as-root devices, fstab lists / for system partition.
197 std::string partition = match[1];
198 return partition.empty() ? "system" : partition;
199}
200
201static bool MergeFsUsage(DynamicPartitionsDeviceInfoProto* proto,
202 std::ostream& cerr) {
203 using namespace std::string_literals;
204 Fstab fstab;
205 if (!ReadDefaultFstab(&fstab)) {
206 cerr << "Cannot read fstab\n";
207 return false;
208 }
209
210 for (const auto& entry : fstab) {
211 auto partition = GetReadonlyPartitionName(entry);
212 if (!partition) {
213 continue;
214 }
215
216 // system is mounted to "/";
217 const char* mount_point = (entry.mount_point == "/system")
218 ? "/" : entry.mount_point.c_str();
219
220 struct statvfs vst;
221 if (statvfs(mount_point, &vst) == -1) {
222 continue;
223 }
224
225 auto partition_proto = FindPartition(proto, *partition);
226 if (partition_proto == nullptr) {
227 partition_proto = proto->add_partitions();
228 partition_proto->set_name(*partition);
229 partition_proto->set_is_dynamic(false);
230 }
231 partition_proto->set_fs_size((uint64_t)vst.f_blocks * vst.f_frsize);
Sandeep Dhavale6c66b452023-04-10 18:56:19 +0000232
233 if (!entry.fs_type.empty()) {
234 partition_proto->set_fs_type(entry.fs_type);
235 } else {
236 partition_proto->set_fs_type("UNKNOWN");
237 }
238
Yifan Hong7ea1a932019-03-15 16:06:50 -0700239 if (vst.f_bavail <= vst.f_blocks) {
240 partition_proto->set_fs_used((uint64_t)(vst.f_blocks - vst.f_bavail) * vst.f_frsize);
241 }
242 }
243 return true;
244}
245#endif
246
247// Print output in JSON format.
248// If successful, this function must write a valid JSON string to "cout" and return 0.
249static int PrintJson(const LpMetadata* metadata, std::ostream& cout,
250 std::ostream& cerr) {
251 DynamicPartitionsDeviceInfoProto proto;
252
253 if (base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
254 proto.set_enabled(true);
255 }
256
257 if (base::GetBoolProperty("ro.boot.dynamic_partitions_retrofit", false)) {
258 proto.set_retrofit(true);
259 }
260
261 if (!MergeMetadata(metadata, &proto)) {
262 cerr << "Warning: Failed to read metadata.\n";
263 }
264#ifdef __ANDROID__
265 if (!MergeFsUsage(&proto, cerr)) {
266 cerr << "Warning: Failed to read filesystem size and usage.\n";
267 }
268#endif
269
270 auto error_or_json = jsonpb::MessageToJsonString(proto);
271 if (!error_or_json.ok()) {
272 cerr << error_or_json.error() << "\n";
273 return EX_SOFTWARE;
274 }
275 cout << *error_or_json;
276 return EX_OK;
277}
278
David Anderson674ae9e2019-09-05 17:57:20 -0700279static int DumpMetadataSize(const LpMetadata& metadata, std::ostream& cout) {
280 auto super_device = GetMetadataSuperBlockDevice(metadata);
David Anderson289570e2019-05-22 14:31:06 -0700281 uint64_t metadata_size = super_device->first_logical_sector * LP_SECTOR_SIZE;
282 cout << metadata_size << std::endl;
283 return EX_OK;
284}
285
David Anderson8a403a82018-11-13 11:39:19 -0800286class FileOrBlockDeviceOpener final : public PartitionOpener {
287public:
288 android::base::unique_fd Open(const std::string& path, int flags) const override {
289 // Try a local file first.
Yifan Hongb84fb572019-03-15 14:19:08 -0700290 android::base::unique_fd fd;
291
292#ifdef __ANDROID__
293 fd.reset(android_get_control_file(path.c_str()));
294 if (fd >= 0) return fd;
295#endif
296 fd.reset(open(path.c_str(), flags));
297 if (fd >= 0) return fd;
298
David Anderson8a403a82018-11-13 11:39:19 -0800299 return PartitionOpener::Open(path, flags);
300 }
301};
302
Yifan Hong6ba2d0c2019-09-23 18:01:20 -0700303std::optional<std::tuple<std::string, uint64_t>>
304ParseLinearExtentData(const LpMetadata& pt, const LpMetadataExtent& extent) {
305 if (extent.target_type != LP_TARGET_TYPE_LINEAR) {
306 return std::nullopt;
307 }
308 const auto& block_device = pt.block_devices[extent.target_source];
309 std::string device_name = GetBlockDevicePartitionName(block_device);
310 return std::make_tuple(std::move(device_name), extent.target_data);
311}
312
David Anderson674ae9e2019-09-05 17:57:20 -0700313static void PrintMetadata(const LpMetadata& pt, std::ostream& cout) {
314 cout << "Metadata version: " << pt.header.major_version << "." << pt.header.minor_version
315 << "\n";
316 cout << "Metadata size: " << (pt.header.header_size + pt.header.tables_size) << " bytes\n";
317 cout << "Metadata max size: " << pt.geometry.metadata_max_size << " bytes\n";
318 cout << "Metadata slot count: " << pt.geometry.metadata_slot_count << "\n";
David Andersonab1b0952019-12-12 17:12:27 -0800319 cout << "Header flags: " << BuildHeaderFlagString(pt.header.flags) << "\n";
David Anderson674ae9e2019-09-05 17:57:20 -0700320 cout << "Partition table:\n";
321 cout << "------------------------\n";
322
Yifan Hong6ba2d0c2019-09-23 18:01:20 -0700323 std::vector<std::tuple<std::string, const LpMetadataExtent*>> extents;
324
David Anderson674ae9e2019-09-05 17:57:20 -0700325 for (const auto& partition : pt.partitions) {
326 std::string name = GetPartitionName(partition);
327 std::string group_name = GetPartitionGroupName(pt.groups[partition.group_index]);
328 cout << " Name: " << name << "\n";
329 cout << " Group: " << group_name << "\n";
330 cout << " Attributes: " << BuildAttributeString(partition.attributes) << "\n";
331 cout << " Extents:\n";
332 uint64_t first_sector = 0;
333 for (size_t i = 0; i < partition.num_extents; i++) {
334 const LpMetadataExtent& extent = pt.extents[partition.first_extent_index + i];
335 cout << " " << first_sector << " .. " << (first_sector + extent.num_sectors - 1)
336 << " ";
337 first_sector += extent.num_sectors;
338 if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
339 const auto& block_device = pt.block_devices[extent.target_source];
340 std::string device_name = GetBlockDevicePartitionName(block_device);
341 cout << "linear " << device_name.c_str() << " " << extent.target_data;
342 } else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
343 cout << "zero";
344 }
Yifan Hong6ba2d0c2019-09-23 18:01:20 -0700345 extents.push_back(std::make_tuple(name, &extent));
David Anderson674ae9e2019-09-05 17:57:20 -0700346 cout << "\n";
347 }
348 cout << "------------------------\n";
349 }
350
Yifan Hong6ba2d0c2019-09-23 18:01:20 -0700351 std::sort(extents.begin(), extents.end(), [&](const auto& x, const auto& y) {
352 auto x_data = ParseLinearExtentData(pt, *std::get<1>(x));
353 auto y_data = ParseLinearExtentData(pt, *std::get<1>(y));
354 return x_data < y_data;
355 });
356
357 cout << "Super partition layout:\n";
358 cout << "------------------------\n";
359 for (auto&& [name, extent] : extents) {
360 auto data = ParseLinearExtentData(pt, *extent);
361 if (!data) continue;
362 auto&& [block_device, offset] = *data;
363 cout << block_device << ": " << offset << " .. " << (offset + extent->num_sectors)
364 << ": " << name << " (" << extent->num_sectors << " sectors)\n";
365 }
366 cout << "------------------------\n";
367
David Anderson674ae9e2019-09-05 17:57:20 -0700368 cout << "Block device table:\n";
369 cout << "------------------------\n";
370 for (const auto& block_device : pt.block_devices) {
371 std::string partition_name = GetBlockDevicePartitionName(block_device);
372 cout << " Partition name: " << partition_name << "\n";
373 cout << " First sector: " << block_device.first_logical_sector << "\n";
374 cout << " Size: " << block_device.size << " bytes\n";
375 cout << " Flags: " << BuildBlockDeviceFlagString(block_device.flags) << "\n";
376 cout << "------------------------\n";
377 }
378
379 cout << "Group table:\n";
380 cout << "------------------------\n";
381 for (const auto& group : pt.groups) {
382 std::string group_name = GetPartitionGroupName(group);
383 cout << " Name: " << group_name << "\n";
384 cout << " Maximum size: " << group.maximum_size << " bytes\n";
385 cout << " Flags: " << BuildGroupFlagString(group.flags) << "\n";
386 cout << "------------------------\n";
387 }
388}
389
390static std::unique_ptr<LpMetadata> ReadDeviceOrFile(const std::string& path, uint32_t slot) {
391 if (IsEmptySuperImage(path)) {
392 return ReadFromImageFile(path);
393 }
394 return ReadMetadata(path, slot);
395}
396
Yifan Hongb48d79f2019-03-19 16:18:11 -0700397int LpdumpMain(int argc, char* argv[], std::ostream& cout, std::ostream& cerr) {
Yifan Hong7ea1a932019-03-15 16:06:50 -0700398 // clang-format off
David Anderson41241232018-06-13 16:50:11 -0700399 struct option options[] = {
David Andersoncd5227d2019-09-05 18:31:12 -0700400 { "all", no_argument, nullptr, 'a' },
David Anderson41241232018-06-13 16:50:11 -0700401 { "slot", required_argument, nullptr, 's' },
402 { "help", no_argument, nullptr, 'h' },
Yifan Hong7ea1a932019-03-15 16:06:50 -0700403 { "json", no_argument, nullptr, 'j' },
David Anderson289570e2019-05-22 14:31:06 -0700404 { "dump-metadata-size", no_argument, nullptr, 'd' },
405 { "is-super-empty", no_argument, nullptr, 'e' },
David Anderson41241232018-06-13 16:50:11 -0700406 { nullptr, 0, nullptr, 0 },
407 };
Yifan Hong7ea1a932019-03-15 16:06:50 -0700408 // clang-format on
David Anderson41241232018-06-13 16:50:11 -0700409
Yifan Hongb84fb572019-03-15 14:19:08 -0700410 // Allow this function to be invoked by lpdumpd multiple times.
411 optind = 1;
412
David Anderson41241232018-06-13 16:50:11 -0700413 int rv;
414 int index;
Yifan Hong7ea1a932019-03-15 16:06:50 -0700415 bool json = false;
David Anderson289570e2019-05-22 14:31:06 -0700416 bool dump_metadata_size = false;
David Andersoncd5227d2019-09-05 18:31:12 -0700417 bool dump_all = false;
David Anderson674ae9e2019-09-05 17:57:20 -0700418 std::optional<uint32_t> slot;
David Anderson289570e2019-05-22 14:31:06 -0700419 while ((rv = getopt_long_only(argc, argv, "s:jhde", options, &index)) != -1) {
David Anderson41241232018-06-13 16:50:11 -0700420 switch (rv) {
David Andersoncd5227d2019-09-05 18:31:12 -0700421 case 'a':
422 dump_all = true;
423 break;
David Anderson41241232018-06-13 16:50:11 -0700424 case 'h':
David Anderson58871e42019-11-19 17:07:14 -0800425 usage(argc, argv, cout);
David Anderson289570e2019-05-22 14:31:06 -0700426 return EX_OK;
David Anderson674ae9e2019-09-05 17:57:20 -0700427 case 's': {
428 uint32_t slot_arg;
429 if (android::base::ParseUint(optarg, &slot_arg)) {
430 slot = slot_arg;
431 } else {
David Anderson41241232018-06-13 16:50:11 -0700432 slot = SlotNumberForSlotSuffix(optarg);
433 }
434 break;
David Anderson674ae9e2019-09-05 17:57:20 -0700435 }
David Anderson289570e2019-05-22 14:31:06 -0700436 case 'e':
David Anderson674ae9e2019-09-05 17:57:20 -0700437 // This is ignored, we now derive whether it's empty automatically.
David Anderson289570e2019-05-22 14:31:06 -0700438 break;
439 case 'd':
440 dump_metadata_size = true;
441 break;
Yifan Hong7ea1a932019-03-15 16:06:50 -0700442 case 'j':
443 json = true;
444 break;
David Anderson289570e2019-05-22 14:31:06 -0700445 case '?':
446 case ':':
447 return usage(argc, argv, cerr);
David Anderson41241232018-06-13 16:50:11 -0700448 }
449 }
450
David Andersoncd5227d2019-09-05 18:31:12 -0700451 if (dump_all) {
452 if (slot.has_value()) {
453 cerr << "Cannot specify both --all and --slot.\n";
454 return usage(argc, argv, cerr);
455 }
456 if (json) {
457 cerr << "Cannot specify both --all and --json.\n";
458 return usage(argc, argv, cerr);
459 }
460
461 // When dumping everything always start from the first slot.
462 slot = 0;
463 }
464
David Anderson674ae9e2019-09-05 17:57:20 -0700465#ifdef __ANDROID__
466 // Use the current slot as a default for A/B devices.
David Anderson998892b2019-09-05 18:53:21 -0700467 auto current_slot_suffix = GetSlotSuffix();
468 if (!slot.has_value() && !current_slot_suffix.empty()) {
469 slot = SlotNumberForSlotSuffix(current_slot_suffix);
David Anderson674ae9e2019-09-05 17:57:20 -0700470 }
471#endif
472
473 // If we still haven't determined a slot yet, use the first one.
474 if (!slot.has_value()) {
475 slot = 0;
476 }
477
David Anderson998892b2019-09-05 18:53:21 -0700478 // Determine the path to the super partition (or image). If an explicit
479 // path is given, we use it for everything. Otherwise, we will infer it
480 // at the time we need to read metadata.
David Anderson674ae9e2019-09-05 17:57:20 -0700481 std::string super_path;
David Anderson998892b2019-09-05 18:53:21 -0700482 bool override_super_name = (optind < argc);
483 if (override_super_name) {
David Anderson674ae9e2019-09-05 17:57:20 -0700484 super_path = argv[optind++];
David Anderson299abc72018-12-12 13:36:43 -0800485 } else {
486#ifdef __ANDROID__
David Anderson998892b2019-09-05 18:53:21 -0700487 super_path = GetSuperPartitionName(slot);
David Anderson299abc72018-12-12 13:36:43 -0800488#else
David Anderson674ae9e2019-09-05 17:57:20 -0700489 cerr << "Must specify a super partition image.\n";
Yifan Hongb48d79f2019-03-19 16:18:11 -0700490 return usage(argc, argv, cerr);
David Anderson299abc72018-12-12 13:36:43 -0800491#endif
David Anderson41241232018-06-13 16:50:11 -0700492 }
Yifan Hong7ea1a932019-03-15 16:06:50 -0700493
David Anderson674ae9e2019-09-05 17:57:20 -0700494 auto pt = ReadDeviceOrFile(super_path, slot.value());
495
Yifan Hong7ea1a932019-03-15 16:06:50 -0700496 // --json option doesn't require metadata to be present.
497 if (json) {
498 return PrintJson(pt.get(), cout, cerr);
499 }
500
David Anderson41241232018-06-13 16:50:11 -0700501 if (!pt) {
Yifan Hongb48d79f2019-03-19 16:18:11 -0700502 cerr << "Failed to read metadata.\n";
David Anderson41241232018-06-13 16:50:11 -0700503 return EX_NOINPUT;
504 }
505
David Anderson289570e2019-05-22 14:31:06 -0700506 if (dump_metadata_size) {
David Anderson674ae9e2019-09-05 17:57:20 -0700507 return DumpMetadataSize(*pt.get(), cout);
David Anderson289570e2019-05-22 14:31:06 -0700508 }
509
David Andersoncd5227d2019-09-05 18:31:12 -0700510 // When running on the device, we can check the slot count. Otherwise we
511 // use the # of metadata slots. (There is an extra slot we don't want to
512 // dump because it is currently unused.)
513#ifdef __ANDROID__
David Anderson998892b2019-09-05 18:53:21 -0700514 uint32_t num_slots = current_slot_suffix.empty() ? 1 : 2;
David Andersoncd5227d2019-09-05 18:31:12 -0700515 if (dump_all && num_slots > 1) {
David Anderson998892b2019-09-05 18:53:21 -0700516 cout << "Current slot: " << current_slot_suffix << "\n";
David Andersoncd5227d2019-09-05 18:31:12 -0700517 }
518#else
519 uint32_t num_slots = pt->geometry.metadata_slot_count;
520#endif
David Anderson998892b2019-09-05 18:53:21 -0700521 // Empty images only have one slot.
522 if (IsEmptySuperImage(super_path)) {
523 num_slots = 1;
524 }
David Andersoncd5227d2019-09-05 18:31:12 -0700525
David Anderson998892b2019-09-05 18:53:21 -0700526 if (num_slots > 1) {
David Anderson674ae9e2019-09-05 17:57:20 -0700527 cout << "Slot " << slot.value() << ":\n";
David Anderson41241232018-06-13 16:50:11 -0700528 }
David Anderson674ae9e2019-09-05 17:57:20 -0700529 PrintMetadata(*pt.get(), cout);
David Andersoncd5227d2019-09-05 18:31:12 -0700530
David Anderson998892b2019-09-05 18:53:21 -0700531 if (dump_all) {
David Andersoncd5227d2019-09-05 18:31:12 -0700532 for (uint32_t i = 1; i < num_slots; i++) {
David Anderson998892b2019-09-05 18:53:21 -0700533 if (!override_super_name) {
534 super_path = GetSuperPartitionName(i);
535 }
536
David Andersoncd5227d2019-09-05 18:31:12 -0700537 pt = ReadDeviceOrFile(super_path, i);
538 if (!pt) {
539 continue;
540 }
541
542 cout << "\nSlot " << i << ":\n";
543 PrintMetadata(*pt.get(), cout);
544 }
545 }
David Anderson41241232018-06-13 16:50:11 -0700546 return EX_OK;
547}
Yifan Hongb48d79f2019-03-19 16:18:11 -0700548
Yifan Hongb84fb572019-03-15 14:19:08 -0700549int LpdumpMain(int argc, char* argv[]) {
Yifan Hongb48d79f2019-03-19 16:18:11 -0700550 return LpdumpMain(argc, argv, std::cout, std::cerr);
551}