blob: 97b5ad409720d937148d20a162377dea9ba0b95f [file] [log] [blame]
Hridya Valsaraju31d2c262018-07-20 13:35:50 -07001/*
2 * Copyright (C) 2018 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 "utility.h"
18
David Anderson0f626632018-08-31 16:44:25 -070019#include <dirent.h>
20#include <sys/stat.h>
21#include <sys/types.h>
22#include <unistd.h>
23
Hridya Valsarajudca328d2018-09-24 16:01:35 -070024#include <android-base/file.h>
David Anderson12211d12018-07-24 15:21:20 -070025#include <android-base/logging.h>
David Andersond25f1c32018-11-09 20:41:33 -080026#include <android-base/properties.h>
Hridya Valsaraju99f37722018-10-08 11:06:38 -070027#include <android-base/strings.h>
David Anderson5cbd2e42018-09-27 10:53:04 -070028#include <fs_mgr.h>
David Anderson23243492019-12-17 00:58:31 -080029#include <fs_mgr/roots.h>
David Anderson88ef0b12018-08-09 10:40:00 -070030#include <fs_mgr_dm_linear.h>
David Andersond25f1c32018-11-09 20:41:33 -080031#include <liblp/builder.h>
David Anderson88ef0b12018-08-09 10:40:00 -070032#include <liblp/liblp.h>
David Anderson12211d12018-07-24 15:21:20 -070033
34#include "fastboot_device.h"
35
David Anderson88ef0b12018-08-09 10:40:00 -070036using namespace android::fs_mgr;
David Andersonc8ac4e72018-09-06 17:25:03 -070037using namespace std::chrono_literals;
David Anderson12211d12018-07-24 15:21:20 -070038using android::base::unique_fd;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070039using android::hardware::boot::V1_0::Slot;
40
David Andersond25f1c32018-11-09 20:41:33 -080041namespace {
42
43bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
David Anderson12211d12018-07-24 15:21:20 -070044 std::optional<std::string> path = FindPhysicalPartition(name);
45 if (!path) {
46 return false;
47 }
48 *handle = PartitionHandle(*path);
49 return true;
50}
51
David Andersond25f1c32018-11-09 20:41:33 -080052bool OpenLogicalPartition(FastbootDevice* device, const std::string& partition_name,
53 PartitionHandle* handle) {
54 std::string slot_suffix = GetSuperSlotSuffix(device, partition_name);
55 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
56 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
David Anderson88ef0b12018-08-09 10:40:00 -070057 if (!path) {
58 return false;
59 }
David Anderson15aa9542019-08-12 17:07:50 -070060
61 CreateLogicalPartitionParams params = {
62 .block_device = *path,
63 .metadata_slot = slot_number,
64 .partition_name = partition_name,
65 .force_writable = true,
66 .timeout_ms = 5s,
67 };
David Anderson88ef0b12018-08-09 10:40:00 -070068 std::string dm_path;
David Anderson15aa9542019-08-12 17:07:50 -070069 if (!CreateLogicalPartition(params, &dm_path)) {
David Andersond25f1c32018-11-09 20:41:33 -080070 LOG(ERROR) << "Could not map partition: " << partition_name;
David Anderson88ef0b12018-08-09 10:40:00 -070071 return false;
72 }
David Anderson470fe2b2019-07-10 18:09:50 -070073 auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); };
David Anderson88ef0b12018-08-09 10:40:00 -070074 *handle = PartitionHandle(dm_path, std::move(closer));
75 return true;
76}
77
David Andersond25f1c32018-11-09 20:41:33 -080078} // namespace
79
Yifan Hongc4073d32021-02-18 12:35:42 -080080bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle,
Konstantin Vyshetsky81cc1192021-11-04 10:27:06 -070081 int flags) {
David Anderson88ef0b12018-08-09 10:40:00 -070082 // We prioritize logical partitions over physical ones, and do this
83 // consistently for other partition operations (like getvar:partition-size).
David Andersond25f1c32018-11-09 20:41:33 -080084 if (LogicalPartitionExists(device, name)) {
85 if (!OpenLogicalPartition(device, name, handle)) {
David Anderson88ef0b12018-08-09 10:40:00 -070086 return false;
87 }
88 } else if (!OpenPhysicalPartition(name, handle)) {
David Anderson12211d12018-07-24 15:21:20 -070089 LOG(ERROR) << "No such partition: " << name;
90 return false;
91 }
92
Yifan Honga5cee932021-02-18 16:03:59 -080093 flags |= (O_EXCL | O_CLOEXEC | O_BINARY);
Yifan Hongc4073d32021-02-18 12:35:42 -080094 unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), flags)));
David Anderson12211d12018-07-24 15:21:20 -070095 if (fd < 0) {
96 PLOG(ERROR) << "Failed to open block device: " << handle->path();
97 return false;
98 }
99 handle->set_fd(std::move(fd));
100 return true;
101}
102
103std::optional<std::string> FindPhysicalPartition(const std::string& name) {
Hridya Valsaraju99f37722018-10-08 11:06:38 -0700104 // Check for an invalid file name
105 if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
106 return {};
107 }
David Anderson12211d12018-07-24 15:21:20 -0700108 std::string path = "/dev/block/by-name/" + name;
Hridya Valsaraju3ffed212018-09-05 12:07:33 -0700109 if (access(path.c_str(), W_OK) < 0) {
David Anderson12211d12018-07-24 15:21:20 -0700110 return {};
111 }
112 return path;
113}
114
David Anderson88ef0b12018-08-09 10:40:00 -0700115static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata,
116 const std::string& name) {
117 for (const auto& partition : metadata.partitions) {
118 if (GetPartitionName(partition) == name) {
119 return &partition;
120 }
121 }
122 return nullptr;
123}
124
David Andersond25f1c32018-11-09 20:41:33 -0800125bool LogicalPartitionExists(FastbootDevice* device, const std::string& name, bool* is_zero_length) {
126 std::string slot_suffix = GetSuperSlotSuffix(device, name);
127 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
128 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
David Anderson88ef0b12018-08-09 10:40:00 -0700129 if (!path) {
130 return false;
131 }
132
David Anderson88ef0b12018-08-09 10:40:00 -0700133 std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
134 if (!metadata) {
135 return false;
136 }
137 const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name);
138 if (!partition) {
139 return false;
140 }
141 if (is_zero_length) {
142 *is_zero_length = (partition->num_extents == 0);
143 }
144 return true;
145}
146
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700147bool GetSlotNumber(const std::string& slot, Slot* number) {
148 if (slot.size() != 1) {
149 return false;
150 }
151 if (slot[0] < 'a' || slot[0] > 'z') {
152 return false;
153 }
154 *number = slot[0] - 'a';
155 return true;
156}
David Anderson0f626632018-08-31 16:44:25 -0700157
158std::vector<std::string> ListPartitions(FastbootDevice* device) {
159 std::vector<std::string> partitions;
160
161 // First get physical partitions.
162 struct dirent* de;
163 std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir);
164 while ((de = readdir(by_name.get())) != nullptr) {
165 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
166 continue;
167 }
168 struct stat s;
169 std::string path = "/dev/block/by-name/" + std::string(de->d_name);
170 if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) {
171 partitions.emplace_back(de->d_name);
172 }
173 }
174
David Andersond25f1c32018-11-09 20:41:33 -0800175 // Find metadata in each super partition (on retrofit devices, there will
176 // be two).
177 std::vector<std::unique_ptr<LpMetadata>> metadata_list;
178
179 uint32_t current_slot = SlotNumberForSlotSuffix(device->GetCurrentSlot());
180 std::string super_name = fs_mgr_get_super_partition_name(current_slot);
181 if (auto metadata = ReadMetadata(super_name, current_slot)) {
182 metadata_list.emplace_back(std::move(metadata));
183 }
184
185 uint32_t other_slot = (current_slot == 0) ? 1 : 0;
186 std::string other_super = fs_mgr_get_super_partition_name(other_slot);
187 if (super_name != other_super) {
188 if (auto metadata = ReadMetadata(other_super, other_slot)) {
189 metadata_list.emplace_back(std::move(metadata));
190 }
191 }
192
193 for (const auto& metadata : metadata_list) {
194 for (const auto& partition : metadata->partitions) {
195 std::string partition_name = GetPartitionName(partition);
196 if (std::find(partitions.begin(), partitions.end(), partition_name) ==
197 partitions.end()) {
David Anderson0f626632018-08-31 16:44:25 -0700198 partitions.emplace_back(partition_name);
199 }
200 }
201 }
202 return partitions;
203}
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700204
205bool GetDeviceLockStatus() {
Oleg Matcovschid0a16c22021-03-25 11:41:38 -0700206 return android::base::GetProperty("ro.boot.verifiedbootstate", "") != "orange";
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700207}
David Andersond25f1c32018-11-09 20:41:33 -0800208
David Anderson4d307b02018-12-17 17:07:34 -0800209bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
David Andersond25f1c32018-11-09 20:41:33 -0800210 const android::fs_mgr::LpMetadata& metadata) {
David Anderson4d307b02018-12-17 17:07:34 -0800211 size_t num_slots = 1;
212 auto boot_control_hal = device->boot_control_hal();
213 if (boot_control_hal) {
214 num_slots = boot_control_hal->getNumberSlots();
215 }
216
David Andersond25f1c32018-11-09 20:41:33 -0800217 bool ok = true;
David Anderson4d307b02018-12-17 17:07:34 -0800218 for (size_t i = 0; i < num_slots; i++) {
David Andersond25f1c32018-11-09 20:41:33 -0800219 ok &= UpdatePartitionTable(super_name, metadata, i);
220 }
221 return ok;
222}
223
224std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name) {
225 // If the super partition does not have a slot suffix, this is not a
226 // retrofit device, and we should take the current slot.
227 std::string current_slot_suffix = device->GetCurrentSlot();
228 uint32_t current_slot_number = SlotNumberForSlotSuffix(current_slot_suffix);
229 std::string super_partition = fs_mgr_get_super_partition_name(current_slot_number);
230 if (GetPartitionSlotSuffix(super_partition).empty()) {
231 return current_slot_suffix;
232 }
233
234 // Otherwise, infer the slot from the partition name.
235 std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
236 if (!slot_suffix.empty()) {
237 return slot_suffix;
238 }
239 return current_slot_suffix;
240}
David Anderson23243492019-12-17 00:58:31 -0800241
242AutoMountMetadata::AutoMountMetadata() {
243 android::fs_mgr::Fstab proc_mounts;
244 if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
245 LOG(ERROR) << "Could not read /proc/mounts";
246 return;
247 }
248
249 if (GetEntryForMountPoint(&proc_mounts, "/metadata")) {
250 mounted_ = true;
251 return;
252 }
253
254 if (!ReadDefaultFstab(&fstab_)) {
255 LOG(ERROR) << "Could not read default fstab";
256 return;
257 }
258 mounted_ = EnsurePathMounted(&fstab_, "/metadata");
259 should_unmount_ = true;
260}
261
262AutoMountMetadata::~AutoMountMetadata() {
263 if (mounted_ && should_unmount_) {
264 EnsurePathUnmounted(&fstab_, "/metadata");
265 }
266}