Hridya Valsaraju | 31d2c26 | 2018-07-20 13:35:50 -0700 | [diff] [blame] | 1 | /* |
| 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 Anderson | 0f62663 | 2018-08-31 16:44:25 -0700 | [diff] [blame] | 19 | #include <dirent.h> |
| 20 | #include <sys/stat.h> |
| 21 | #include <sys/types.h> |
| 22 | #include <unistd.h> |
| 23 | |
Hridya Valsaraju | dca328d | 2018-09-24 16:01:35 -0700 | [diff] [blame] | 24 | #include <android-base/file.h> |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 25 | #include <android-base/logging.h> |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 26 | #include <android-base/properties.h> |
Hridya Valsaraju | 99f3772 | 2018-10-08 11:06:38 -0700 | [diff] [blame] | 27 | #include <android-base/strings.h> |
David Anderson | 5cbd2e4 | 2018-09-27 10:53:04 -0700 | [diff] [blame] | 28 | #include <fs_mgr.h> |
David Anderson | 2324349 | 2019-12-17 00:58:31 -0800 | [diff] [blame] | 29 | #include <fs_mgr/roots.h> |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 30 | #include <fs_mgr_dm_linear.h> |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 31 | #include <liblp/builder.h> |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 32 | #include <liblp/liblp.h> |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 33 | |
| 34 | #include "fastboot_device.h" |
| 35 | |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 36 | using namespace android::fs_mgr; |
David Anderson | c8ac4e7 | 2018-09-06 17:25:03 -0700 | [diff] [blame] | 37 | using namespace std::chrono_literals; |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 38 | using android::base::unique_fd; |
Hridya Valsaraju | 31d2c26 | 2018-07-20 13:35:50 -0700 | [diff] [blame] | 39 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 40 | namespace { |
| 41 | |
| 42 | bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) { |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 43 | std::optional<std::string> path = FindPhysicalPartition(name); |
| 44 | if (!path) { |
| 45 | return false; |
| 46 | } |
| 47 | *handle = PartitionHandle(*path); |
| 48 | return true; |
| 49 | } |
| 50 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 51 | bool OpenLogicalPartition(FastbootDevice* device, const std::string& partition_name, |
| 52 | PartitionHandle* handle) { |
| 53 | std::string slot_suffix = GetSuperSlotSuffix(device, partition_name); |
| 54 | uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix); |
| 55 | auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number)); |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 56 | if (!path) { |
| 57 | return false; |
| 58 | } |
David Anderson | 15aa954 | 2019-08-12 17:07:50 -0700 | [diff] [blame] | 59 | |
| 60 | CreateLogicalPartitionParams params = { |
| 61 | .block_device = *path, |
| 62 | .metadata_slot = slot_number, |
| 63 | .partition_name = partition_name, |
| 64 | .force_writable = true, |
| 65 | .timeout_ms = 5s, |
| 66 | }; |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 67 | std::string dm_path; |
David Anderson | 15aa954 | 2019-08-12 17:07:50 -0700 | [diff] [blame] | 68 | if (!CreateLogicalPartition(params, &dm_path)) { |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 69 | LOG(ERROR) << "Could not map partition: " << partition_name; |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 70 | return false; |
| 71 | } |
David Anderson | 470fe2b | 2019-07-10 18:09:50 -0700 | [diff] [blame] | 72 | auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name); }; |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 73 | *handle = PartitionHandle(dm_path, std::move(closer)); |
| 74 | return true; |
| 75 | } |
| 76 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 77 | } // namespace |
| 78 | |
Yifan Hong | c4073d3 | 2021-02-18 12:35:42 -0800 | [diff] [blame] | 79 | bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle, |
Konstantin Vyshetsky | 81cc119 | 2021-11-04 10:27:06 -0700 | [diff] [blame] | 80 | int flags) { |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 81 | // We prioritize logical partitions over physical ones, and do this |
| 82 | // consistently for other partition operations (like getvar:partition-size). |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 83 | if (LogicalPartitionExists(device, name)) { |
| 84 | if (!OpenLogicalPartition(device, name, handle)) { |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 85 | return false; |
| 86 | } |
| 87 | } else if (!OpenPhysicalPartition(name, handle)) { |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 88 | LOG(ERROR) << "No such partition: " << name; |
| 89 | return false; |
| 90 | } |
| 91 | |
Konstantin Vyshetsky | 1cee2ed | 2022-03-17 17:57:28 -0700 | [diff] [blame] | 92 | return handle->Open(flags); |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | std::optional<std::string> FindPhysicalPartition(const std::string& name) { |
Hridya Valsaraju | 99f3772 | 2018-10-08 11:06:38 -0700 | [diff] [blame] | 96 | // Check for an invalid file name |
| 97 | if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) { |
| 98 | return {}; |
| 99 | } |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 100 | std::string path = "/dev/block/by-name/" + name; |
Hridya Valsaraju | 3ffed21 | 2018-09-05 12:07:33 -0700 | [diff] [blame] | 101 | if (access(path.c_str(), W_OK) < 0) { |
David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 102 | return {}; |
| 103 | } |
| 104 | return path; |
| 105 | } |
| 106 | |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 107 | static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata, |
| 108 | const std::string& name) { |
| 109 | for (const auto& partition : metadata.partitions) { |
| 110 | if (GetPartitionName(partition) == name) { |
| 111 | return &partition; |
| 112 | } |
| 113 | } |
| 114 | return nullptr; |
| 115 | } |
| 116 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 117 | bool LogicalPartitionExists(FastbootDevice* device, const std::string& name, bool* is_zero_length) { |
| 118 | std::string slot_suffix = GetSuperSlotSuffix(device, name); |
| 119 | uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix); |
| 120 | auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number)); |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 121 | if (!path) { |
| 122 | return false; |
| 123 | } |
| 124 | |
David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 125 | std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number); |
| 126 | if (!metadata) { |
| 127 | return false; |
| 128 | } |
| 129 | const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name); |
| 130 | if (!partition) { |
| 131 | return false; |
| 132 | } |
| 133 | if (is_zero_length) { |
| 134 | *is_zero_length = (partition->num_extents == 0); |
| 135 | } |
| 136 | return true; |
| 137 | } |
| 138 | |
Kelvin Zhang | 6befe78 | 2022-06-21 14:20:54 -0700 | [diff] [blame] | 139 | bool GetSlotNumber(const std::string& slot, int32_t* number) { |
Hridya Valsaraju | 31d2c26 | 2018-07-20 13:35:50 -0700 | [diff] [blame] | 140 | if (slot.size() != 1) { |
| 141 | return false; |
| 142 | } |
| 143 | if (slot[0] < 'a' || slot[0] > 'z') { |
| 144 | return false; |
| 145 | } |
| 146 | *number = slot[0] - 'a'; |
| 147 | return true; |
| 148 | } |
David Anderson | 0f62663 | 2018-08-31 16:44:25 -0700 | [diff] [blame] | 149 | |
| 150 | std::vector<std::string> ListPartitions(FastbootDevice* device) { |
| 151 | std::vector<std::string> partitions; |
| 152 | |
| 153 | // First get physical partitions. |
| 154 | struct dirent* de; |
| 155 | std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir); |
| 156 | while ((de = readdir(by_name.get())) != nullptr) { |
| 157 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { |
| 158 | continue; |
| 159 | } |
| 160 | struct stat s; |
| 161 | std::string path = "/dev/block/by-name/" + std::string(de->d_name); |
| 162 | if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) { |
| 163 | partitions.emplace_back(de->d_name); |
| 164 | } |
| 165 | } |
| 166 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 167 | // Find metadata in each super partition (on retrofit devices, there will |
| 168 | // be two). |
| 169 | std::vector<std::unique_ptr<LpMetadata>> metadata_list; |
| 170 | |
| 171 | uint32_t current_slot = SlotNumberForSlotSuffix(device->GetCurrentSlot()); |
| 172 | std::string super_name = fs_mgr_get_super_partition_name(current_slot); |
| 173 | if (auto metadata = ReadMetadata(super_name, current_slot)) { |
| 174 | metadata_list.emplace_back(std::move(metadata)); |
| 175 | } |
| 176 | |
| 177 | uint32_t other_slot = (current_slot == 0) ? 1 : 0; |
| 178 | std::string other_super = fs_mgr_get_super_partition_name(other_slot); |
| 179 | if (super_name != other_super) { |
| 180 | if (auto metadata = ReadMetadata(other_super, other_slot)) { |
| 181 | metadata_list.emplace_back(std::move(metadata)); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | for (const auto& metadata : metadata_list) { |
| 186 | for (const auto& partition : metadata->partitions) { |
| 187 | std::string partition_name = GetPartitionName(partition); |
| 188 | if (std::find(partitions.begin(), partitions.end(), partition_name) == |
| 189 | partitions.end()) { |
David Anderson | 0f62663 | 2018-08-31 16:44:25 -0700 | [diff] [blame] | 190 | partitions.emplace_back(partition_name); |
| 191 | } |
| 192 | } |
| 193 | } |
| 194 | return partitions; |
| 195 | } |
Hridya Valsaraju | dca328d | 2018-09-24 16:01:35 -0700 | [diff] [blame] | 196 | |
| 197 | bool GetDeviceLockStatus() { |
maxwen | dcc2daa | 2019-12-16 19:42:28 +0100 | [diff] [blame^] | 198 | return false; |
Hridya Valsaraju | dca328d | 2018-09-24 16:01:35 -0700 | [diff] [blame] | 199 | } |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 200 | |
David Anderson | 4d307b0 | 2018-12-17 17:07:34 -0800 | [diff] [blame] | 201 | bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name, |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 202 | const android::fs_mgr::LpMetadata& metadata) { |
David Anderson | 4d307b0 | 2018-12-17 17:07:34 -0800 | [diff] [blame] | 203 | size_t num_slots = 1; |
| 204 | auto boot_control_hal = device->boot_control_hal(); |
| 205 | if (boot_control_hal) { |
Kelvin Zhang | 6befe78 | 2022-06-21 14:20:54 -0700 | [diff] [blame] | 206 | num_slots = boot_control_hal->GetNumSlots(); |
David Anderson | 4d307b0 | 2018-12-17 17:07:34 -0800 | [diff] [blame] | 207 | } |
| 208 | |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 209 | bool ok = true; |
David Anderson | 4d307b0 | 2018-12-17 17:07:34 -0800 | [diff] [blame] | 210 | for (size_t i = 0; i < num_slots; i++) { |
David Anderson | d25f1c3 | 2018-11-09 20:41:33 -0800 | [diff] [blame] | 211 | ok &= UpdatePartitionTable(super_name, metadata, i); |
| 212 | } |
| 213 | return ok; |
| 214 | } |
| 215 | |
| 216 | std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name) { |
| 217 | // If the super partition does not have a slot suffix, this is not a |
| 218 | // retrofit device, and we should take the current slot. |
| 219 | std::string current_slot_suffix = device->GetCurrentSlot(); |
| 220 | uint32_t current_slot_number = SlotNumberForSlotSuffix(current_slot_suffix); |
| 221 | std::string super_partition = fs_mgr_get_super_partition_name(current_slot_number); |
| 222 | if (GetPartitionSlotSuffix(super_partition).empty()) { |
| 223 | return current_slot_suffix; |
| 224 | } |
| 225 | |
| 226 | // Otherwise, infer the slot from the partition name. |
| 227 | std::string slot_suffix = GetPartitionSlotSuffix(partition_name); |
| 228 | if (!slot_suffix.empty()) { |
| 229 | return slot_suffix; |
| 230 | } |
| 231 | return current_slot_suffix; |
| 232 | } |
David Anderson | 2324349 | 2019-12-17 00:58:31 -0800 | [diff] [blame] | 233 | |
| 234 | AutoMountMetadata::AutoMountMetadata() { |
| 235 | android::fs_mgr::Fstab proc_mounts; |
| 236 | if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) { |
| 237 | LOG(ERROR) << "Could not read /proc/mounts"; |
| 238 | return; |
| 239 | } |
| 240 | |
| 241 | if (GetEntryForMountPoint(&proc_mounts, "/metadata")) { |
| 242 | mounted_ = true; |
| 243 | return; |
| 244 | } |
| 245 | |
| 246 | if (!ReadDefaultFstab(&fstab_)) { |
| 247 | LOG(ERROR) << "Could not read default fstab"; |
| 248 | return; |
| 249 | } |
| 250 | mounted_ = EnsurePathMounted(&fstab_, "/metadata"); |
| 251 | should_unmount_ = true; |
| 252 | } |
| 253 | |
| 254 | AutoMountMetadata::~AutoMountMetadata() { |
| 255 | if (mounted_ && should_unmount_) { |
| 256 | EnsurePathUnmounted(&fstab_, "/metadata"); |
| 257 | } |
| 258 | } |