blob: c54119a33ddeec3501ad1bede979ab5001c2cae7 [file] [log] [blame]
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <getopt.h>
#include <inttypes.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sysexits.h>
#include <unistd.h>
#include <string>
#include <android-base/parseint.h>
#include <liblp/reader.h>
using namespace android;
using namespace android::fs_mgr;
static int usage(int /* argc */, char* argv[]) {
fprintf(stderr,
"%s - command-line tool for dumping Android Logical Partition images.\n"
"\n"
"Usage:\n"
" %s [-s,--slot] file-or-device\n"
"\n"
"Options:\n"
" -s, --slot=N Slot number or suffix.\n",
argv[0], argv[0]);
return EX_USAGE;
}
static std::string BuildAttributeString(uint32_t attrs) {
return (attrs & LP_PARTITION_ATTR_READONLY) ? "readonly" : "none";
}
static bool IsBlockDevice(const char* file) {
struct stat s;
return !stat(file, &s) && S_ISBLK(s.st_mode);
}
int main(int argc, char* argv[]) {
struct option options[] = {
{ "slot", required_argument, nullptr, 's' },
{ "help", no_argument, nullptr, 'h' },
{ nullptr, 0, nullptr, 0 },
};
int rv;
int index;
uint32_t slot = 0;
while ((rv = getopt_long_only(argc, argv, "s:h", options, &index)) != -1) {
switch (rv) {
case 'h':
return usage(argc, argv);
case 's':
if (!android::base::ParseUint(optarg, &slot)) {
slot = SlotNumberForSlotSuffix(optarg);
}
break;
}
}
if (optind >= argc) {
return usage(argc, argv);
}
const char* file = argv[optind++];
std::unique_ptr<LpMetadata> pt;
if (IsBlockDevice(file)) {
pt = ReadMetadata(file, slot);
} else {
pt = ReadFromImageFile(file);
}
if (!pt) {
fprintf(stderr, "Failed to read metadata.\n");
return EX_NOINPUT;
}
printf("Metadata version: %u.%u\n", pt->header.major_version, pt->header.minor_version);
printf("Metadata size: %u bytes\n", pt->header.header_size + pt->header.tables_size);
printf("Metadata max size: %u bytes\n", pt->geometry.metadata_max_size);
printf("Metadata slot count: %u\n", pt->geometry.metadata_slot_count);
printf("First logical sector: %" PRIu64 "\n", pt->geometry.first_logical_sector);
printf("Last logical sector: %" PRIu64 "\n", pt->geometry.last_logical_sector);
printf("Partition table:\n");
printf("------------------------\n");
for (const auto& partition : pt->partitions) {
std::string name = GetPartitionName(partition);
std::string guid = GetPartitionGuid(partition);
printf(" Name: %s\n", name.c_str());
printf(" GUID: %s\n", guid.c_str());
printf(" Attributes: %s\n", BuildAttributeString(partition.attributes).c_str());
printf(" 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];
printf(" %" PRIu64 " .. %" PRIu64 " ", first_sector,
(first_sector + extent.num_sectors - 1));
first_sector += extent.num_sectors;
if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
printf("linear %" PRIu64, extent.target_data);
} else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
printf("zero");
}
printf("\n");
}
printf("------------------------\n");
}
return EX_OK;
}