Loading fs_mgr/libsnapshot/Android.bp +23 −0 Original line number Diff line number Diff line Loading @@ -114,3 +114,26 @@ cc_test { "libstorage_literals_headers", ], } cc_binary { name: "snapshotctl", srcs: [ "snapshotctl.cpp", ], static_libs: [ "libdm", "libext2_uuid", "libfiemap_binder", "libfstab", "libsnapshot", ], shared_libs: [ "libbase", "libbinder", "libext4_utils", "libfs_mgr", "libutils", "liblog", "liblp", ], } fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +3 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,9 @@ class SnapshotManager final { // call to CreateLogicalPartitions when snapshots are present. bool CreateLogicalAndSnapshotPartitions(const std::string& super_device); // Dump debug information. bool Dump(std::ostream& os); private: FRIEND_TEST(SnapshotTest, CleanFirstStageMount); FRIEND_TEST(SnapshotTest, CreateSnapshot); Loading fs_mgr/libsnapshot/snapshot.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -1482,7 +1482,7 @@ auto SnapshotManager::OpenFile(const std::string& file, int open_flags, int lock PLOG(ERROR) << "Open failed: " << file; return nullptr; } if (flock(fd, lock_flags) < 0) { if (lock_flags != 0 && flock(fd, lock_flags) < 0) { PLOG(ERROR) << "Acquire flock failed: " << file; return nullptr; } Loading Loading @@ -1962,5 +1962,47 @@ bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_na return UnmapPartitionWithSnapshot(lock.get(), target_partition_name); } bool SnapshotManager::Dump(std::ostream& os) { // Don't actually lock. Dump() is for debugging purposes only, so it is okay // if it is racy. auto file = OpenStateFile(O_RDONLY, 0); if (!file) return false; std::stringstream ss; ss << "Update state: " << ReadUpdateState(file.get()) << std::endl; auto boot_file = GetSnapshotBootIndicatorPath(); std::string boot_indicator; if (android::base::ReadFileToString(boot_file, &boot_indicator)) { ss << "Boot indicator: old slot = " << boot_indicator << std::endl; } bool ok = true; std::vector<std::string> snapshots; if (!ListSnapshots(file.get(), &snapshots)) { LOG(ERROR) << "Could not list snapshots"; snapshots.clear(); ok = false; } for (const auto& name : snapshots) { ss << "Snapshot: " << name << std::endl; SnapshotStatus status; if (!ReadSnapshotStatus(file.get(), name, &status)) { ok = false; continue; } ss << " state: " << to_string(status.state) << std::endl; ss << " device size (bytes): " << status.device_size << std::endl; ss << " snapshot size (bytes): " << status.snapshot_size << std::endl; ss << " cow partition size (bytes): " << status.cow_partition_size << std::endl; ss << " cow file size (bytes): " << status.cow_file_size << std::endl; ss << " allocated sectors: " << status.sectors_allocated << std::endl; ss << " metadata sectors: " << status.metadata_sectors << std::endl; } os << ss.rdbuf(); return ok; } } // namespace snapshot } // namespace android fs_mgr/libsnapshot/snapshotctl.cpp 0 → 100644 +115 −0 Original line number Diff line number Diff line // // Copyright (C) 2019 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 <sysexits.h> #include <chrono> #include <iostream> #include <map> #include <android-base/logging.h> #include <libsnapshot/snapshot.h> using namespace std::string_literals; int Usage() { std::cerr << "snapshotctl: Control snapshots.\n" "Usage: snapshotctl [action] [flags]\n" "Actions:\n" " dump\n" " Print snapshot states.\n" " merge [--logcat]\n" " Initialize merge and wait for it to be completed.\n" " If --logcat is specified, log to logcat. Otherwise, log to stdout.\n"; return EX_USAGE; } namespace android { namespace snapshot { bool DumpCmdHandler(int /*argc*/, char** argv) { android::base::InitLogging(argv, &android::base::StderrLogger); return SnapshotManager::New()->Dump(std::cout); } bool MergeCmdHandler(int argc, char** argv) { auto begin = std::chrono::steady_clock::now(); bool log_to_logcat = false; for (int i = 2; i < argc; ++i) { if (argv[i] == "--logcat"s) { log_to_logcat = true; } } if (log_to_logcat) { android::base::InitLogging(argv); } else { android::base::InitLogging(argv, &android::base::StdioLogger); } auto sm = SnapshotManager::New(); auto state = sm->GetUpdateState(); if (state == UpdateState::None) { LOG(INFO) << "Can't find any snapshot to merge."; return true; } if (state == UpdateState::Unverified) { if (!sm->InitiateMerge()) { LOG(ERROR) << "Failed to initiate merge."; return false; } } // All other states can be handled by ProcessUpdateState. LOG(INFO) << "Waiting for any merge to complete. This can take up to 1 minute."; state = SnapshotManager::New()->ProcessUpdateState(); if (state == UpdateState::MergeCompleted) { auto end = std::chrono::steady_clock::now(); auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count(); LOG(INFO) << "Snapshot merged in " << passed << " ms."; return true; } LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\"."; return false; } static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = { // clang-format off {"dump", DumpCmdHandler}, {"merge", MergeCmdHandler}, // clang-format on }; } // namespace snapshot } // namespace android int main(int argc, char** argv) { using namespace android::snapshot; if (argc < 2) { return Usage(); } for (const auto& cmd : kCmdMap) { if (cmd.first == argv[1]) { return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE; } } return Usage(); } Loading
fs_mgr/libsnapshot/Android.bp +23 −0 Original line number Diff line number Diff line Loading @@ -114,3 +114,26 @@ cc_test { "libstorage_literals_headers", ], } cc_binary { name: "snapshotctl", srcs: [ "snapshotctl.cpp", ], static_libs: [ "libdm", "libext2_uuid", "libfiemap_binder", "libfstab", "libsnapshot", ], shared_libs: [ "libbase", "libbinder", "libext4_utils", "libfs_mgr", "libutils", "liblog", "liblp", ], }
fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +3 −0 Original line number Diff line number Diff line Loading @@ -192,6 +192,9 @@ class SnapshotManager final { // call to CreateLogicalPartitions when snapshots are present. bool CreateLogicalAndSnapshotPartitions(const std::string& super_device); // Dump debug information. bool Dump(std::ostream& os); private: FRIEND_TEST(SnapshotTest, CleanFirstStageMount); FRIEND_TEST(SnapshotTest, CreateSnapshot); Loading
fs_mgr/libsnapshot/snapshot.cpp +43 −1 Original line number Diff line number Diff line Loading @@ -1482,7 +1482,7 @@ auto SnapshotManager::OpenFile(const std::string& file, int open_flags, int lock PLOG(ERROR) << "Open failed: " << file; return nullptr; } if (flock(fd, lock_flags) < 0) { if (lock_flags != 0 && flock(fd, lock_flags) < 0) { PLOG(ERROR) << "Acquire flock failed: " << file; return nullptr; } Loading Loading @@ -1962,5 +1962,47 @@ bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_na return UnmapPartitionWithSnapshot(lock.get(), target_partition_name); } bool SnapshotManager::Dump(std::ostream& os) { // Don't actually lock. Dump() is for debugging purposes only, so it is okay // if it is racy. auto file = OpenStateFile(O_RDONLY, 0); if (!file) return false; std::stringstream ss; ss << "Update state: " << ReadUpdateState(file.get()) << std::endl; auto boot_file = GetSnapshotBootIndicatorPath(); std::string boot_indicator; if (android::base::ReadFileToString(boot_file, &boot_indicator)) { ss << "Boot indicator: old slot = " << boot_indicator << std::endl; } bool ok = true; std::vector<std::string> snapshots; if (!ListSnapshots(file.get(), &snapshots)) { LOG(ERROR) << "Could not list snapshots"; snapshots.clear(); ok = false; } for (const auto& name : snapshots) { ss << "Snapshot: " << name << std::endl; SnapshotStatus status; if (!ReadSnapshotStatus(file.get(), name, &status)) { ok = false; continue; } ss << " state: " << to_string(status.state) << std::endl; ss << " device size (bytes): " << status.device_size << std::endl; ss << " snapshot size (bytes): " << status.snapshot_size << std::endl; ss << " cow partition size (bytes): " << status.cow_partition_size << std::endl; ss << " cow file size (bytes): " << status.cow_file_size << std::endl; ss << " allocated sectors: " << status.sectors_allocated << std::endl; ss << " metadata sectors: " << status.metadata_sectors << std::endl; } os << ss.rdbuf(); return ok; } } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/snapshotctl.cpp 0 → 100644 +115 −0 Original line number Diff line number Diff line // // Copyright (C) 2019 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 <sysexits.h> #include <chrono> #include <iostream> #include <map> #include <android-base/logging.h> #include <libsnapshot/snapshot.h> using namespace std::string_literals; int Usage() { std::cerr << "snapshotctl: Control snapshots.\n" "Usage: snapshotctl [action] [flags]\n" "Actions:\n" " dump\n" " Print snapshot states.\n" " merge [--logcat]\n" " Initialize merge and wait for it to be completed.\n" " If --logcat is specified, log to logcat. Otherwise, log to stdout.\n"; return EX_USAGE; } namespace android { namespace snapshot { bool DumpCmdHandler(int /*argc*/, char** argv) { android::base::InitLogging(argv, &android::base::StderrLogger); return SnapshotManager::New()->Dump(std::cout); } bool MergeCmdHandler(int argc, char** argv) { auto begin = std::chrono::steady_clock::now(); bool log_to_logcat = false; for (int i = 2; i < argc; ++i) { if (argv[i] == "--logcat"s) { log_to_logcat = true; } } if (log_to_logcat) { android::base::InitLogging(argv); } else { android::base::InitLogging(argv, &android::base::StdioLogger); } auto sm = SnapshotManager::New(); auto state = sm->GetUpdateState(); if (state == UpdateState::None) { LOG(INFO) << "Can't find any snapshot to merge."; return true; } if (state == UpdateState::Unverified) { if (!sm->InitiateMerge()) { LOG(ERROR) << "Failed to initiate merge."; return false; } } // All other states can be handled by ProcessUpdateState. LOG(INFO) << "Waiting for any merge to complete. This can take up to 1 minute."; state = SnapshotManager::New()->ProcessUpdateState(); if (state == UpdateState::MergeCompleted) { auto end = std::chrono::steady_clock::now(); auto passed = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin).count(); LOG(INFO) << "Snapshot merged in " << passed << " ms."; return true; } LOG(ERROR) << "Snapshot failed to merge with state \"" << state << "\"."; return false; } static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = { // clang-format off {"dump", DumpCmdHandler}, {"merge", MergeCmdHandler}, // clang-format on }; } // namespace snapshot } // namespace android int main(int argc, char** argv) { using namespace android::snapshot; if (argc < 2) { return Usage(); } for (const auto& cmd : kCmdMap) { if (cmd.first == argv[1]) { return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE; } } return Usage(); }