1 // Copyright (C) 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "utility.h"
16
17 #include <errno.h>
18 #include <time.h>
19
20 #include <iomanip>
21 #include <sstream>
22
23 #include <android-base/file.h>
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/strings.h>
27 #include <fs_mgr/roots.h>
28
29 using android::dm::kSectorSize;
30 using android::fiemap::FiemapStatus;
31 using android::fs_mgr::EnsurePathMounted;
32 using android::fs_mgr::EnsurePathUnmounted;
33 using android::fs_mgr::Fstab;
34 using android::fs_mgr::GetEntryForPath;
35 using android::fs_mgr::MetadataBuilder;
36 using android::fs_mgr::Partition;
37 using android::fs_mgr::ReadDefaultFstab;
38 using google::protobuf::RepeatedPtrField;
39
40 namespace android {
41 namespace snapshot {
42
Release()43 void AutoDevice::Release() {
44 name_.clear();
45 }
46
~AutoDeviceList()47 AutoDeviceList::~AutoDeviceList() {
48 // Destroy devices in the reverse order because newer devices may have dependencies
49 // on older devices.
50 for (auto it = devices_.rbegin(); it != devices_.rend(); ++it) {
51 it->reset();
52 }
53 }
54
Release()55 void AutoDeviceList::Release() {
56 for (auto&& p : devices_) {
57 p->Release();
58 }
59 }
60
~AutoUnmapDevice()61 AutoUnmapDevice::~AutoUnmapDevice() {
62 if (name_.empty()) return;
63 if (!dm_->DeleteDeviceIfExists(name_)) {
64 LOG(ERROR) << "Failed to auto unmap device " << name_;
65 }
66 }
67
~AutoUnmapImage()68 AutoUnmapImage::~AutoUnmapImage() {
69 if (name_.empty()) return;
70 if (!images_->UnmapImageIfExists(name_)) {
71 LOG(ERROR) << "Failed to auto unmap cow image " << name_;
72 }
73 }
74
ListPartitionsWithSuffix(MetadataBuilder * builder,const std::string & suffix)75 std::vector<Partition*> ListPartitionsWithSuffix(MetadataBuilder* builder,
76 const std::string& suffix) {
77 std::vector<Partition*> ret;
78 for (const auto& group : builder->ListGroups()) {
79 for (auto* partition : builder->ListPartitionsInGroup(group)) {
80 if (!base::EndsWith(partition->name(), suffix)) {
81 continue;
82 }
83 ret.push_back(partition);
84 }
85 }
86 return ret;
87 }
88
~AutoDeleteSnapshot()89 AutoDeleteSnapshot::~AutoDeleteSnapshot() {
90 if (!name_.empty() && !manager_->DeleteSnapshot(lock_, name_)) {
91 LOG(ERROR) << "Failed to auto delete snapshot " << name_;
92 }
93 }
94
InitializeKernelCow(const std::string & device)95 Return InitializeKernelCow(const std::string& device) {
96 // When the kernel creates a persistent dm-snapshot, it requires a CoW file
97 // to store the modifications. The kernel interface does not specify how
98 // the CoW is used, and there is no standard associated.
99 // By looking at the current implementation, the CoW file is treated as:
100 // - a _NEW_ snapshot if its first 32 bits are zero, so the newly created
101 // dm-snapshot device will look like a perfect copy of the origin device;
102 // - an _EXISTING_ snapshot if the first 32 bits are equal to a
103 // kernel-specified magic number and the CoW file metadata is set as valid,
104 // so it can be used to resume the last state of a snapshot device;
105 // - an _INVALID_ snapshot otherwise.
106 // To avoid zero-filling the whole CoW file when a new dm-snapshot is
107 // created, here we zero-fill only the first chunk to be compliant with
108 // lvm.
109 constexpr ssize_t kDmSnapZeroFillSize = kSectorSize * kSnapshotChunkSize;
110
111 std::vector<uint8_t> zeros(kDmSnapZeroFillSize, 0);
112 android::base::unique_fd fd(open(device.c_str(), O_WRONLY | O_BINARY));
113 if (fd < 0) {
114 PLOG(ERROR) << "Can't open COW device: " << device;
115 return Return(FiemapStatus::FromErrno(errno));
116 }
117
118 LOG(INFO) << "Zero-filling COW device: " << device;
119 if (!android::base::WriteFully(fd, zeros.data(), kDmSnapZeroFillSize)) {
120 PLOG(ERROR) << "Can't zero-fill COW device for " << device;
121 return Return(FiemapStatus::FromErrno(errno));
122 }
123 return Return::Ok();
124 }
125
New(const std::string & path)126 std::unique_ptr<AutoUnmountDevice> AutoUnmountDevice::New(const std::string& path) {
127 Fstab fstab;
128 if (!ReadDefaultFstab(&fstab)) {
129 LOG(ERROR) << "Cannot read default fstab";
130 return nullptr;
131 }
132
133 if (GetEntryForPath(&fstab, path) == nullptr) {
134 LOG(INFO) << "EnsureMetadataMounted can't find entry for " << path << ", skipping";
135 return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice("", {}));
136 }
137
138 if (!EnsurePathMounted(&fstab, path)) {
139 LOG(ERROR) << "Cannot mount " << path;
140 return nullptr;
141 }
142 return std::unique_ptr<AutoUnmountDevice>(new AutoUnmountDevice(path, std::move(fstab)));
143 }
144
~AutoUnmountDevice()145 AutoUnmountDevice::~AutoUnmountDevice() {
146 if (name_.empty()) return;
147 if (!EnsurePathUnmounted(&fstab_, name_)) {
148 LOG(ERROR) << "Cannot unmount " << name_;
149 }
150 }
151
WriteStringToFileAtomic(const std::string & content,const std::string & path)152 bool WriteStringToFileAtomic(const std::string& content, const std::string& path) {
153 std::string tmp_path = path + ".tmp";
154 if (!android::base::WriteStringToFile(content, tmp_path)) {
155 return false;
156 }
157 if (rename(tmp_path.c_str(), path.c_str()) == -1) {
158 PLOG(ERROR) << "rename failed from " << tmp_path << " to " << path;
159 return false;
160 }
161 return true;
162 }
163
operator <<(std::ostream & os,const Now &)164 std::ostream& operator<<(std::ostream& os, const Now&) {
165 struct tm now;
166 time_t t = time(nullptr);
167 localtime_r(&t, &now);
168 return os << std::put_time(&now, "%Y%m%d-%H%M%S");
169 }
170
AppendExtent(RepeatedPtrField<chromeos_update_engine::Extent> * extents,uint64_t start_block,uint64_t num_blocks)171 void AppendExtent(RepeatedPtrField<chromeos_update_engine::Extent>* extents, uint64_t start_block,
172 uint64_t num_blocks) {
173 if (extents->size() > 0) {
174 auto last_extent = extents->rbegin();
175 auto next_block = last_extent->start_block() + last_extent->num_blocks();
176 if (start_block == next_block) {
177 last_extent->set_num_blocks(last_extent->num_blocks() + num_blocks);
178 return;
179 }
180 }
181 auto* new_extent = extents->Add();
182 new_extent->set_start_block(start_block);
183 new_extent->set_num_blocks(num_blocks);
184 }
185
IsCompressionEnabled()186 bool IsCompressionEnabled() {
187 return android::base::GetBoolProperty("ro.virtual_ab.compression.enabled", false);
188 }
189
GetOtherPartitionName(const std::string & name)190 std::string GetOtherPartitionName(const std::string& name) {
191 auto suffix = android::fs_mgr::GetPartitionSlotSuffix(name);
192 CHECK(suffix == "_a" || suffix == "_b");
193
194 auto other_suffix = (suffix == "_a") ? "_b" : "_a";
195 return name.substr(0, name.size() - suffix.size()) + other_suffix;
196 }
197
198 } // namespace snapshot
199 } // namespace android
200