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