/* * 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; } } std::string findGroup(std::unique_ptr& builder) { auto groups = builder->ListGroups(); std::string maxGroup = ""; uint64_t maxGroupSize = 0; for(auto groupName: groups) { auto group = builder->FindGroup(groupName); if(group->maximum_size() > maxGroupSize) { maxGroup = groupName; maxGroupSize = group->maximum_size(); } } return maxGroup; } int main(int argc, char **argv) { if(argc<=1) { std::cerr << "Usage: " << argv[0] << " " << std::endl; exit(1); } auto builder = makeBuilder(); auto group = findGroup(builder); std::cout << "Best group seems to be " << group << std::endl; 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, group, 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, group, 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; }