blob: 2ebd57d12beb3376b63ecc370dcee4ed6f7334eb [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 Anderson88ef0b12018-08-09 10:40:00 -070029#include <fs_mgr_dm_linear.h>
David Andersond25f1c32018-11-09 20:41:33 -080030#include <liblp/builder.h>
David Anderson88ef0b12018-08-09 10:40:00 -070031#include <liblp/liblp.h>
David Anderson12211d12018-07-24 15:21:20 -070032
33#include "fastboot_device.h"
34
David Anderson88ef0b12018-08-09 10:40:00 -070035using namespace android::fs_mgr;
David Andersonc8ac4e72018-09-06 17:25:03 -070036using namespace std::chrono_literals;
David Anderson12211d12018-07-24 15:21:20 -070037using android::base::unique_fd;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070038using android::hardware::boot::V1_0::Slot;
39
David Andersond25f1c32018-11-09 20:41:33 -080040namespace {
41
42bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
David Anderson12211d12018-07-24 15:21:20 -070043 std::optional<std::string> path = FindPhysicalPartition(name);
44 if (!path) {
45 return false;
46 }
47 *handle = PartitionHandle(*path);
48 return true;
49}
50
David Andersond25f1c32018-11-09 20:41:33 -080051bool 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 Anderson88ef0b12018-08-09 10:40:00 -070056 if (!path) {
57 return false;
58 }
David Anderson88ef0b12018-08-09 10:40:00 -070059 std::string dm_path;
David Andersond25f1c32018-11-09 20:41:33 -080060 if (!CreateLogicalPartition(path->c_str(), slot_number, partition_name, true, 5s, &dm_path)) {
61 LOG(ERROR) << "Could not map partition: " << partition_name;
David Anderson88ef0b12018-08-09 10:40:00 -070062 return false;
63 }
David Andersond25f1c32018-11-09 20:41:33 -080064 auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
David Anderson88ef0b12018-08-09 10:40:00 -070065 *handle = PartitionHandle(dm_path, std::move(closer));
66 return true;
67}
68
David Andersond25f1c32018-11-09 20:41:33 -080069} // namespace
70
David Anderson88ef0b12018-08-09 10:40:00 -070071bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) {
72 // We prioritize logical partitions over physical ones, and do this
73 // consistently for other partition operations (like getvar:partition-size).
David Andersond25f1c32018-11-09 20:41:33 -080074 if (LogicalPartitionExists(device, name)) {
75 if (!OpenLogicalPartition(device, name, handle)) {
David Anderson88ef0b12018-08-09 10:40:00 -070076 return false;
77 }
78 } else if (!OpenPhysicalPartition(name, handle)) {
David Anderson12211d12018-07-24 15:21:20 -070079 LOG(ERROR) << "No such partition: " << name;
80 return false;
81 }
82
83 unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), O_WRONLY | O_EXCL)));
84 if (fd < 0) {
85 PLOG(ERROR) << "Failed to open block device: " << handle->path();
86 return false;
87 }
88 handle->set_fd(std::move(fd));
89 return true;
90}
91
92std::optional<std::string> FindPhysicalPartition(const std::string& name) {
Hridya Valsaraju99f37722018-10-08 11:06:38 -070093 // Check for an invalid file name
94 if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
95 return {};
96 }
David Anderson12211d12018-07-24 15:21:20 -070097 std::string path = "/dev/block/by-name/" + name;
Hridya Valsaraju3ffed212018-09-05 12:07:33 -070098 if (access(path.c_str(), W_OK) < 0) {
David Anderson12211d12018-07-24 15:21:20 -070099 return {};
100 }
101 return path;
102}
103
David Anderson88ef0b12018-08-09 10:40:00 -0700104static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata,
105 const std::string& name) {
106 for (const auto& partition : metadata.partitions) {
107 if (GetPartitionName(partition) == name) {
108 return &partition;
109 }
110 }
111 return nullptr;
112}
113
David Andersond25f1c32018-11-09 20:41:33 -0800114bool LogicalPartitionExists(FastbootDevice* device, const std::string& name, bool* is_zero_length) {
115 std::string slot_suffix = GetSuperSlotSuffix(device, name);
116 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
117 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number));
David Anderson88ef0b12018-08-09 10:40:00 -0700118 if (!path) {
119 return false;
120 }
121
David Anderson88ef0b12018-08-09 10:40:00 -0700122 std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
123 if (!metadata) {
124 return false;
125 }
126 const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name);
127 if (!partition) {
128 return false;
129 }
130 if (is_zero_length) {
131 *is_zero_length = (partition->num_extents == 0);
132 }
133 return true;
134}
135
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700136bool GetSlotNumber(const std::string& slot, Slot* number) {
137 if (slot.size() != 1) {
138 return false;
139 }
140 if (slot[0] < 'a' || slot[0] > 'z') {
141 return false;
142 }
143 *number = slot[0] - 'a';
144 return true;
145}
David Anderson0f626632018-08-31 16:44:25 -0700146
147std::vector<std::string> ListPartitions(FastbootDevice* device) {
148 std::vector<std::string> partitions;
149
150 // First get physical partitions.
151 struct dirent* de;
152 std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir);
153 while ((de = readdir(by_name.get())) != nullptr) {
154 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
155 continue;
156 }
157 struct stat s;
158 std::string path = "/dev/block/by-name/" + std::string(de->d_name);
159 if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) {
160 partitions.emplace_back(de->d_name);
161 }
162 }
163
David Andersond25f1c32018-11-09 20:41:33 -0800164 // Find metadata in each super partition (on retrofit devices, there will
165 // be two).
166 std::vector<std::unique_ptr<LpMetadata>> metadata_list;
167
168 uint32_t current_slot = SlotNumberForSlotSuffix(device->GetCurrentSlot());
169 std::string super_name = fs_mgr_get_super_partition_name(current_slot);
170 if (auto metadata = ReadMetadata(super_name, current_slot)) {
171 metadata_list.emplace_back(std::move(metadata));
172 }
173
174 uint32_t other_slot = (current_slot == 0) ? 1 : 0;
175 std::string other_super = fs_mgr_get_super_partition_name(other_slot);
176 if (super_name != other_super) {
177 if (auto metadata = ReadMetadata(other_super, other_slot)) {
178 metadata_list.emplace_back(std::move(metadata));
179 }
180 }
181
182 for (const auto& metadata : metadata_list) {
183 for (const auto& partition : metadata->partitions) {
184 std::string partition_name = GetPartitionName(partition);
185 if (std::find(partitions.begin(), partitions.end(), partition_name) ==
186 partitions.end()) {
David Anderson0f626632018-08-31 16:44:25 -0700187 partitions.emplace_back(partition_name);
188 }
189 }
190 }
191 return partitions;
192}
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700193
194bool GetDeviceLockStatus() {
195 std::string cmdline;
Hridya Valsarajubb12c5e2018-10-08 12:16:10 -0700196 // Return lock status true if unable to read kernel command line.
197 if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
198 return true;
199 }
Hridya Valsarajudca328d2018-09-24 16:01:35 -0700200 return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
201}
David Andersond25f1c32018-11-09 20:41:33 -0800202
David Anderson4d307b02018-12-17 17:07:34 -0800203bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
David Andersond25f1c32018-11-09 20:41:33 -0800204 const android::fs_mgr::LpMetadata& metadata) {
David Anderson4d307b02018-12-17 17:07:34 -0800205 size_t num_slots = 1;
206 auto boot_control_hal = device->boot_control_hal();
207 if (boot_control_hal) {
208 num_slots = boot_control_hal->getNumberSlots();
209 }
210
David Andersond25f1c32018-11-09 20:41:33 -0800211 bool ok = true;
David Anderson4d307b02018-12-17 17:07:34 -0800212 for (size_t i = 0; i < num_slots; i++) {
David Andersond25f1c32018-11-09 20:41:33 -0800213 ok &= UpdatePartitionTable(super_name, metadata, i);
214 }
215 return ok;
216}
217
218std::string GetSuperSlotSuffix(FastbootDevice* device, const std::string& partition_name) {
219 // If the super partition does not have a slot suffix, this is not a
220 // retrofit device, and we should take the current slot.
221 std::string current_slot_suffix = device->GetCurrentSlot();
222 uint32_t current_slot_number = SlotNumberForSlotSuffix(current_slot_suffix);
223 std::string super_partition = fs_mgr_get_super_partition_name(current_slot_number);
224 if (GetPartitionSlotSuffix(super_partition).empty()) {
225 return current_slot_suffix;
226 }
227
228 // Otherwise, infer the slot from the partition name.
229 std::string slot_suffix = GetPartitionSlotSuffix(partition_name);
230 if (!slot_suffix.empty()) {
231 return slot_suffix;
232 }
233 return current_slot_suffix;
234}