| 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> | 
| Hridya Valsaraju | 99f3772 | 2018-10-08 11:06:38 -0700 | [diff] [blame] | 26 | #include <android-base/strings.h> | 
| David Anderson | 5cbd2e4 | 2018-09-27 10:53:04 -0700 | [diff] [blame] | 27 | #include <fs_mgr.h> | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 28 | #include <fs_mgr_dm_linear.h> | 
|  | 29 | #include <liblp/liblp.h> | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 30 |  | 
|  | 31 | #include "fastboot_device.h" | 
|  | 32 |  | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 33 | using namespace android::fs_mgr; | 
| David Anderson | c8ac4e7 | 2018-09-06 17:25:03 -0700 | [diff] [blame] | 34 | using namespace std::chrono_literals; | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 35 | using android::base::unique_fd; | 
| Hridya Valsaraju | 31d2c26 | 2018-07-20 13:35:50 -0700 | [diff] [blame] | 36 | using android::hardware::boot::V1_0::Slot; | 
|  | 37 |  | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 38 | static bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) { | 
|  | 39 | std::optional<std::string> path = FindPhysicalPartition(name); | 
|  | 40 | if (!path) { | 
|  | 41 | return false; | 
|  | 42 | } | 
|  | 43 | *handle = PartitionHandle(*path); | 
|  | 44 | return true; | 
|  | 45 | } | 
|  | 46 |  | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 47 | static bool OpenLogicalPartition(const std::string& name, const std::string& slot, | 
|  | 48 | PartitionHandle* handle) { | 
| David Anderson | 5cbd2e4 | 2018-09-27 10:53:04 -0700 | [diff] [blame] | 49 | std::optional<std::string> path = FindPhysicalPartition(fs_mgr_get_super_partition_name()); | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 50 | if (!path) { | 
|  | 51 | return false; | 
|  | 52 | } | 
|  | 53 | uint32_t slot_number = SlotNumberForSlotSuffix(slot); | 
|  | 54 | std::string dm_path; | 
| David Anderson | c8ac4e7 | 2018-09-06 17:25:03 -0700 | [diff] [blame] | 55 | if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, 5s, &dm_path)) { | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 56 | LOG(ERROR) << "Could not map partition: " << name; | 
|  | 57 | return false; | 
|  | 58 | } | 
| David Anderson | c8ac4e7 | 2018-09-06 17:25:03 -0700 | [diff] [blame] | 59 | auto closer = [name]() -> void { DestroyLogicalPartition(name, 5s); }; | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 60 | *handle = PartitionHandle(dm_path, std::move(closer)); | 
|  | 61 | return true; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) { | 
|  | 65 | // We prioritize logical partitions over physical ones, and do this | 
|  | 66 | // consistently for other partition operations (like getvar:partition-size). | 
|  | 67 | if (LogicalPartitionExists(name, device->GetCurrentSlot())) { | 
|  | 68 | if (!OpenLogicalPartition(name, device->GetCurrentSlot(), handle)) { | 
|  | 69 | return false; | 
|  | 70 | } | 
|  | 71 | } else if (!OpenPhysicalPartition(name, handle)) { | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 72 | LOG(ERROR) << "No such partition: " << name; | 
|  | 73 | return false; | 
|  | 74 | } | 
|  | 75 |  | 
|  | 76 | unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), O_WRONLY | O_EXCL))); | 
|  | 77 | if (fd < 0) { | 
|  | 78 | PLOG(ERROR) << "Failed to open block device: " << handle->path(); | 
|  | 79 | return false; | 
|  | 80 | } | 
|  | 81 | handle->set_fd(std::move(fd)); | 
|  | 82 | return true; | 
|  | 83 | } | 
|  | 84 |  | 
|  | 85 | std::optional<std::string> FindPhysicalPartition(const std::string& name) { | 
| Hridya Valsaraju | 99f3772 | 2018-10-08 11:06:38 -0700 | [diff] [blame] | 86 | // Check for an invalid file name | 
|  | 87 | if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) { | 
|  | 88 | return {}; | 
|  | 89 | } | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 90 | std::string path = "/dev/block/by-name/" + name; | 
| Hridya Valsaraju | 3ffed21 | 2018-09-05 12:07:33 -0700 | [diff] [blame] | 91 | if (access(path.c_str(), W_OK) < 0) { | 
| David Anderson | 12211d1 | 2018-07-24 15:21:20 -0700 | [diff] [blame] | 92 | return {}; | 
|  | 93 | } | 
|  | 94 | return path; | 
|  | 95 | } | 
|  | 96 |  | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 97 | static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata, | 
|  | 98 | const std::string& name) { | 
|  | 99 | for (const auto& partition : metadata.partitions) { | 
|  | 100 | if (GetPartitionName(partition) == name) { | 
|  | 101 | return &partition; | 
|  | 102 | } | 
|  | 103 | } | 
|  | 104 | return nullptr; | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix, | 
|  | 108 | bool* is_zero_length) { | 
| David Anderson | 5cbd2e4 | 2018-09-27 10:53:04 -0700 | [diff] [blame] | 109 | auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name()); | 
| David Anderson | 88ef0b1 | 2018-08-09 10:40:00 -0700 | [diff] [blame] | 110 | if (!path) { | 
|  | 111 | return false; | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix); | 
|  | 115 | std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number); | 
|  | 116 | if (!metadata) { | 
|  | 117 | return false; | 
|  | 118 | } | 
|  | 119 | const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name); | 
|  | 120 | if (!partition) { | 
|  | 121 | return false; | 
|  | 122 | } | 
|  | 123 | if (is_zero_length) { | 
|  | 124 | *is_zero_length = (partition->num_extents == 0); | 
|  | 125 | } | 
|  | 126 | return true; | 
|  | 127 | } | 
|  | 128 |  | 
| Hridya Valsaraju | 31d2c26 | 2018-07-20 13:35:50 -0700 | [diff] [blame] | 129 | bool GetSlotNumber(const std::string& slot, Slot* number) { | 
|  | 130 | if (slot.size() != 1) { | 
|  | 131 | return false; | 
|  | 132 | } | 
|  | 133 | if (slot[0] < 'a' || slot[0] > 'z') { | 
|  | 134 | return false; | 
|  | 135 | } | 
|  | 136 | *number = slot[0] - 'a'; | 
|  | 137 | return true; | 
|  | 138 | } | 
| David Anderson | 0f62663 | 2018-08-31 16:44:25 -0700 | [diff] [blame] | 139 |  | 
|  | 140 | std::vector<std::string> ListPartitions(FastbootDevice* device) { | 
|  | 141 | std::vector<std::string> partitions; | 
|  | 142 |  | 
|  | 143 | // First get physical partitions. | 
|  | 144 | struct dirent* de; | 
|  | 145 | std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir); | 
|  | 146 | while ((de = readdir(by_name.get())) != nullptr) { | 
|  | 147 | if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { | 
|  | 148 | continue; | 
|  | 149 | } | 
|  | 150 | struct stat s; | 
|  | 151 | std::string path = "/dev/block/by-name/" + std::string(de->d_name); | 
|  | 152 | if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) { | 
|  | 153 | partitions.emplace_back(de->d_name); | 
|  | 154 | } | 
|  | 155 | } | 
|  | 156 |  | 
|  | 157 | // Next get logical partitions. | 
| David Anderson | 5cbd2e4 | 2018-09-27 10:53:04 -0700 | [diff] [blame] | 158 | if (auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name())) { | 
| David Anderson | 0f62663 | 2018-08-31 16:44:25 -0700 | [diff] [blame] | 159 | uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot()); | 
|  | 160 | if (auto metadata = ReadMetadata(path->c_str(), slot_number)) { | 
|  | 161 | for (const auto& partition : metadata->partitions) { | 
|  | 162 | std::string partition_name = GetPartitionName(partition); | 
|  | 163 | partitions.emplace_back(partition_name); | 
|  | 164 | } | 
|  | 165 | } | 
|  | 166 | } | 
|  | 167 | return partitions; | 
|  | 168 | } | 
| Hridya Valsaraju | dca328d | 2018-09-24 16:01:35 -0700 | [diff] [blame] | 169 |  | 
|  | 170 | bool GetDeviceLockStatus() { | 
|  | 171 | std::string cmdline; | 
| Hridya Valsaraju | bb12c5e | 2018-10-08 12:16:10 -0700 | [diff] [blame] | 172 | // Return lock status true if unable to read kernel command line. | 
|  | 173 | if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) { | 
|  | 174 | return true; | 
|  | 175 | } | 
| Hridya Valsaraju | dca328d | 2018-09-24 16:01:35 -0700 | [diff] [blame] | 176 | return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos; | 
|  | 177 | } |