From 84435b1f570bea79ca8db96ff5c2d348018ad284 Mon Sep 17 00:00:00 2001 From: Pierre-Hugues Husson Date: Sat, 9 May 2020 14:24:38 +0200 Subject: [PATCH] Add lptools to modify dynamic partitions --- cmds/Android.bp | 28 +++++++ cmds/lptools.cc | 195 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 223 insertions(+) create mode 100644 cmds/lptools.cc diff --git a/cmds/Android.bp b/cmds/Android.bp index 6586e64..522c3c9 100644 --- a/cmds/Android.bp +++ b/cmds/Android.bp @@ -182,3 +182,31 @@ cc_binary { "libhidlbase", ], } + +cc_binary { + name: "lptools", + cflags: [ + "-Werror", + "-Wextra", + ], + device_supported: true, + shared_libs: [ + "libbase", + "liblog", + "liblp", + "libsparse", + "libfs_mgr", + "libutils", + "libcutils", + ], + static_libs: [ + "libdm", + ], + srcs: [ + "lptools.cc", + ], + cppflags: [ + "-D_FILE_OFFSET_BITS=64", + ], +} + diff --git a/cmds/lptools.cc b/cmds/lptools.cc new file mode 100644 index 0000000..840c97f --- /dev/null +++ b/cmds/lptools.cc @@ -0,0 +1,195 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace android; +using namespace android::fs_mgr; + +class FileOrBlockDeviceOpener final : public PartitionOpener { +public: + android::base::unique_fd Open(const std::string& path, int flags) const override { + // Try a local file first. + android::base::unique_fd fd; + +#ifdef __ANDROID__ + fd.reset(android_get_control_file(path.c_str())); + if (fd >= 0) return fd; +#endif + fd.reset(open(path.c_str(), flags)); + if (fd >= 0) return fd; + + return PartitionOpener::Open(path, flags); + } +}; + +static FileOrBlockDeviceOpener opener; +std::unique_ptr makeBuilder() { + MetadataBuilder::OverrideABForTesting(false); + auto builder = MetadataBuilder::New(opener, "super", 0); + if(builder == nullptr) { + std::cout << "Failed creating super builder" << std::endl; + } + return builder; +} + +void saveToDisk(std::unique_ptr builder) { + auto newMetadata = builder->Export(); + int nSlots = 2;//pt->geometry.metadata_slot_count; + for(int slot=0; slot < nSlots; slot++) { + std::cout << "Saving the updated partition table " << UpdatePartitionTable(opener, "super", *newMetadata, slot) << " for slot " << slot << std::endl; + } +} + +int main(int argc, char **argv) { + if(argc<=1) { + std::cerr << "Usage: " << argv[0] << " " << std::endl; + exit(1); + } + auto builder = makeBuilder(); + if(strcmp(argv[1], "create") == 0) { + if(argc != 4) { + std::cerr << "Usage: " << argv[0] << " create " << std::endl; + exit(1); + } + auto partName = argv[2]; + auto size = strtoll(argv[3], NULL, 0); + auto partition = builder->FindPartition(partName); + if(partition != nullptr) { + std::cerr << "Partition " << partName << " already exists." << std::endl; + exit(1); + } + partition = builder->AddPartition(partName, "main", 0); + std::cout << "Growing partition " << builder->ResizePartition(partition, size) << std::endl; + saveToDisk(std::move(builder)); + + std::string dmPath; + auto dmCreateRes = android::fs_mgr::CreateLogicalPartition( + "/dev/block/by-name/super", + 0, partName, + true, + std::chrono::milliseconds(10000), &dmPath); + std::cout << "Creating dm partition for " << partName << " answered " << dmCreateRes << " at " << dmPath << std::endl; + exit(0); + } else if(strcmp(argv[1], "remove") == 0) { + if(argc != 3) { + std::cerr << "Usage: " << argv[0] << " remove " << std::endl; + exit(1); + } + auto partName = argv[2]; + auto dmState = android::dm::DeviceMapper::Instance().GetState(partName); + if(dmState == android::dm::DmDeviceState::ACTIVE) { + android::fs_mgr::DestroyLogicalPartition(partName, std::chrono::milliseconds(2000)); + } + builder->RemovePartition(partName); + saveToDisk(std::move(builder)); + exit(0); + } else if(strcmp(argv[1], "resize") == 0) { + if(argc != 4) { + std::cerr << "Usage: " << argv[0] << " resize " << std::endl; + exit(1); + } + auto partName = argv[2]; + auto size = strtoll(argv[3], NULL, 0); + auto partition = builder->FindPartition(partName); + std::cout << "Resizing partition " << builder->ResizePartition(partition, size) << std::endl; + saveToDisk(std::move(builder)); + exit(0); + } else if(strcmp(argv[1], "replace") == 0) { + if(argc != 4) { + std::cerr << "Usage: " << argv[0] << " replace " << std::endl; + std::cerr << "This will delete and rename to " << std::endl; + exit(1); + } + auto src = argv[2]; + auto dst = argv[3]; + auto srcPartition = builder->FindPartition(src); + std::vector> originalExtents; + + const auto& extents = srcPartition->extents(); + for(unsigned i=0; iAsLinearExtent(); + std::cerr << (linear != nullptr) << std::endl; + if(linear != nullptr) { + auto copyLinear = std::make_unique(linear->num_sectors(), linear->device_index(), linear->physical_sector()); + originalExtents.push_back(std::move(copyLinear)); + } else { + auto copyZero = std::make_unique(extend->num_sectors()); + originalExtents.push_back(std::move(copyZero)); + } + } + builder->RemovePartition(src); + builder->RemovePartition(dst); + auto newDstPartition = builder->AddPartition(dst, "main", 0); + for(auto&& extent: originalExtents) { + newDstPartition->AddExtent(std::move(extent)); + } + saveToDisk(std::move(builder)); + exit(0); + } else if(strcmp(argv[1], "map") == 0) { + if(argc != 3) { + std::cerr << "Usage: " << argv[0] << " map " << std::endl; + exit(1); + } + auto partName = argv[2]; + std::string dmPath; + auto dmCreateRes = android::fs_mgr::CreateLogicalPartition( + "/dev/block/by-name/super", + 0, partName, + true, + std::chrono::milliseconds(10000), &dmPath); + std::cout << "Creating dm partition for " << partName << " answered " << dmCreateRes << " at " << dmPath << std::endl; + exit(0); + } else if(strcmp(argv[1], "unmap") == 0) { + if(argc != 3) { + std::cerr << "Usage: " << argv[0] << " unmap " << std::endl; + exit(1); + } + auto partName = argv[2]; + auto dmState = android::dm::DeviceMapper::Instance().GetState(partName); + if(dmState == android::dm::DmDeviceState::ACTIVE) { + android::fs_mgr::DestroyLogicalPartition(partName, std::chrono::milliseconds(2000)); + } + exit(0); + } + + return 0; +}