1 //
2 // Copyright (C) 2019 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 <sysexits.h>
18 
19 #include <chrono>
20 #include <iostream>
21 #include <map>
22 #include <sstream>
23 
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/unique_fd.h>
27 
28 #include <fs_mgr.h>
29 #include <fs_mgr_dm_linear.h>
30 #include <fstab/fstab.h>
31 #include <liblp/builder.h>
32 #include <libsnapshot/cow_format.h>
33 #include <libsnapshot/snapshot.h>
34 #include <storage_literals/storage_literals.h>
35 
36 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
37 #include <BootControlClient.h>
38 #endif
39 
40 using namespace std::chrono_literals;
41 using namespace std::string_literals;
42 using namespace android::storage_literals;
43 using android::fs_mgr::CreateLogicalPartitionParams;
44 using android::fs_mgr::FindPartition;
45 using android::fs_mgr::GetPartitionSize;
46 using android::fs_mgr::PartitionOpener;
47 using android::fs_mgr::ReadMetadata;
48 using android::fs_mgr::SlotNumberForSlotSuffix;
49 
Usage()50 int Usage() {
51     std::cerr << "snapshotctl: Control snapshots.\n"
52                  "Usage: snapshotctl [action] [flags]\n"
53                  "Actions:\n"
54                  "  dump\n"
55                  "    Print snapshot states.\n"
56                  "  merge\n"
57                  "    Deprecated.\n"
58                  "  map\n"
59                  "    Map all partitions at /dev/block/mapper\n";
60     return EX_USAGE;
61 }
62 
63 namespace android {
64 namespace snapshot {
65 
DumpCmdHandler(int,char ** argv)66 bool DumpCmdHandler(int /*argc*/, char** argv) {
67     android::base::InitLogging(argv, &android::base::StderrLogger);
68     return SnapshotManager::New()->Dump(std::cout);
69 }
70 
MapCmdHandler(int,char ** argv)71 bool MapCmdHandler(int, char** argv) {
72     android::base::InitLogging(argv, &android::base::StderrLogger);
73     using namespace std::chrono_literals;
74     return SnapshotManager::New()->MapAllSnapshots(5000ms);
75 }
76 
UnmapCmdHandler(int,char ** argv)77 bool UnmapCmdHandler(int, char** argv) {
78     android::base::InitLogging(argv, &android::base::StderrLogger);
79     return SnapshotManager::New()->UnmapAllSnapshots();
80 }
81 
MergeCmdHandler(int,char ** argv)82 bool MergeCmdHandler(int /*argc*/, char** argv) {
83     android::base::InitLogging(argv, &android::base::StderrLogger);
84     LOG(WARNING) << "Deprecated. Call update_engine_client --merge instead.";
85     return false;
86 }
87 
88 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
CreateTestUpdate(SnapshotManager * sm)89 bool CreateTestUpdate(SnapshotManager* sm) {
90     chromeos_update_engine::DeltaArchiveManifest manifest;
91 
92     // We only copy system, to simplify things.
93     manifest.set_partial_update(true);
94 
95     auto dap = manifest.mutable_dynamic_partition_metadata();
96     dap->set_snapshot_enabled(true);
97     dap->set_vabc_enabled(true);
98     dap->set_vabc_compression_param("none");
99     dap->set_cow_version(kCowVersionMajor);
100 
101     auto source_slot = fs_mgr_get_slot_suffix();
102     auto source_slot_number = SlotNumberForSlotSuffix(source_slot);
103     auto target_slot = fs_mgr_get_other_slot_suffix();
104     auto target_slot_number = SlotNumberForSlotSuffix(target_slot);
105     auto super_source = fs_mgr_get_super_partition_name(source_slot_number);
106 
107     // Get current partition information.
108     PartitionOpener opener;
109     auto source_metadata = ReadMetadata(opener, super_source, source_slot_number);
110     if (!source_metadata) {
111         std::cerr << "Could not read source partition metadata.\n";
112         return false;
113     }
114 
115     auto system_source_name = "system" + source_slot;
116     auto system_source = FindPartition(*source_metadata.get(), system_source_name);
117     if (!system_source) {
118         std::cerr << "Could not find system partition: " << system_source_name << ".\n";
119         return false;
120     }
121     auto system_source_size = GetPartitionSize(*source_metadata.get(), *system_source);
122 
123     // Since we only add copy operations, 64MB should be enough.
124     auto system_update = manifest.mutable_partitions()->Add();
125     system_update->set_partition_name("system");
126     system_update->set_estimate_cow_size(64_MiB);
127     system_update->mutable_new_partition_info()->set_size(system_source_size);
128 
129     if (!sm->CreateUpdateSnapshots(manifest)) {
130         std::cerr << "Could not create update snapshots.\n";
131         return false;
132     }
133 
134     // Write the "new" system partition.
135     auto system_target_name = "system" + target_slot;
136     auto source_device = "/dev/block/mapper/" + system_source_name;
137     CreateLogicalPartitionParams clpp = {
138             .block_device = fs_mgr_get_super_partition_name(target_slot_number),
139             .metadata_slot = {target_slot_number},
140             .partition_name = system_target_name,
141             .partition_opener = &opener,
142             .timeout_ms = 10s,
143     };
144     auto writer = sm->OpenSnapshotWriter(clpp, {source_device});
145     if (!writer) {
146         std::cerr << "Could not open snapshot writer.\n";
147         return false;
148     }
149     if (!writer->Initialize()) {
150         std::cerr << "Could not initialize snapshot for writing.\n";
151         return false;
152     }
153 
154     for (uint64_t block = 0; block < system_source_size / 4096; block++) {
155         if (!writer->AddCopy(block, block)) {
156             std::cerr << "Unable to add copy operation for block " << block << ".\n";
157             return false;
158         }
159     }
160     if (!writer->Finalize()) {
161         std::cerr << "Could not finalize COW for " << system_target_name << ".\n";
162         return false;
163     }
164     writer = nullptr;
165 
166     // Finished writing this partition, unmap.
167     if (!sm->UnmapUpdateSnapshot(system_target_name)) {
168         std::cerr << "Could not unmap snapshot for " << system_target_name << ".\n";
169         return false;
170     }
171 
172     // All snapshots have been written.
173     if (!sm->FinishedSnapshotWrites(false /* wipe */)) {
174         std::cerr << "Could not finalize snapshot writes.\n";
175         return false;
176     }
177 
178     auto hal = hal::BootControlClient::WaitForService();
179     if (!hal) {
180         std::cerr << "Could not find IBootControl HAL.\n";
181         return false;
182     }
183     auto cr = hal->SetActiveBootSlot(target_slot_number);
184     if (!cr.IsOk()) {
185         std::cerr << "Could not set active boot slot: " << cr.errMsg;
186         return false;
187     }
188 
189     std::cerr << "It is now safe to reboot your device. If using a physical device, make\n"
190               << "sure that all physical partitions are flashed to both A and B slots.\n";
191     return true;
192 }
193 
TestOtaHandler(int,char **)194 bool TestOtaHandler(int /* argc */, char** /* argv */) {
195     auto sm = SnapshotManager::New();
196 
197     if (!sm->BeginUpdate()) {
198         std::cerr << "Error starting update.\n";
199         return false;
200     }
201 
202     if (!CreateTestUpdate(sm.get())) {
203         sm->CancelUpdate();
204         return false;
205     }
206     return true;
207 }
208 #endif
209 
210 static std::map<std::string, std::function<bool(int, char**)>> kCmdMap = {
211         // clang-format off
212         {"dump", DumpCmdHandler},
213         {"merge", MergeCmdHandler},
214         {"map", MapCmdHandler},
215 #ifdef SNAPSHOTCTL_USERDEBUG_OR_ENG
216         {"test-blank-ota", TestOtaHandler},
217 #endif
218         {"unmap", UnmapCmdHandler},
219         // clang-format on
220 };
221 
222 }  // namespace snapshot
223 }  // namespace android
224 
main(int argc,char ** argv)225 int main(int argc, char** argv) {
226     using namespace android::snapshot;
227     if (argc < 2) {
228         return Usage();
229     }
230 
231     for (const auto& cmd : kCmdMap) {
232         if (cmd.first == argv[1]) {
233             return cmd.second(argc, argv) ? EX_OK : EX_SOFTWARE;
234         }
235     }
236 
237     return Usage();
238 }
239