blob: 30c59606bf4ea0fb4286d96d02e6797e6bee07d8 [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>
Hridya Valsaraju99f37722018-10-08 11:06:38 -070026#include <android-base/strings.h>
David Anderson5cbd2e42018-09-27 10:53:04 -070027#include <fs_mgr.h>
David Anderson88ef0b12018-08-09 10:40:00 -070028#include <fs_mgr_dm_linear.h>
29#include <liblp/liblp.h>
David Anderson12211d12018-07-24 15:21:20 -070030
31#include "fastboot_device.h"
32
David Anderson88ef0b12018-08-09 10:40:00 -070033using namespace android::fs_mgr;
David Andersonc8ac4e72018-09-06 17:25:03 -070034using namespace std::chrono_literals;
David Anderson12211d12018-07-24 15:21:20 -070035using android::base::unique_fd;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070036using android::hardware::boot::V1_0::Slot;
37
David Anderson12211d12018-07-24 15:21:20 -070038static 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 Anderson88ef0b12018-08-09 10:40:00 -070047static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
48 PartitionHandle* handle) {
David Anderson5cbd2e42018-09-27 10:53:04 -070049 std::optional<std::string> path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
David Anderson88ef0b12018-08-09 10:40:00 -070050 if (!path) {
51 return false;
52 }
53 uint32_t slot_number = SlotNumberForSlotSuffix(slot);
54 std::string dm_path;
David Andersonc8ac4e72018-09-06 17:25:03 -070055 if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, 5s, &dm_path)) {
David Anderson88ef0b12018-08-09 10:40:00 -070056 LOG(ERROR) << "Could not map partition: " << name;
57 return false;
58 }
David Andersonc8ac4e72018-09-06 17:25:03 -070059 auto closer = [name]() -> void { DestroyLogicalPartition(name, 5s); };
David Anderson88ef0b12018-08-09 10:40:00 -070060 *handle = PartitionHandle(dm_path, std::move(closer));
61 return true;
62}
63
64bool 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 Anderson12211d12018-07-24 15:21:20 -070072 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
85std::optional<std::string> FindPhysicalPartition(const std::string& name) {
Hridya Valsaraju99f37722018-10-08 11:06:38 -070086 // Check for an invalid file name
87 if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
88 return {};
89 }
David Anderson12211d12018-07-24 15:21:20 -070090 std::string path = "/dev/block/by-name/" + name;
Hridya Valsaraju3ffed212018-09-05 12:07:33 -070091 if (access(path.c_str(), W_OK) < 0) {
David Anderson12211d12018-07-24 15:21:20 -070092 return {};
93 }
94 return path;
95}
96
David Anderson88ef0b12018-08-09 10:40:00 -070097static 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
107bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
108 bool* is_zero_length) {
David Anderson5cbd2e42018-09-27 10:53:04 -0700109 auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name());
David Anderson88ef0b12018-08-09 10:40:00 -0700110 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 Valsaraju31d2c262018-07-20 13:35:50 -0700129bool 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 Anderson0f626632018-08-31 16:44:25 -0700139
140std::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 Anderson5cbd2e42018-09-27 10:53:04 -0700158 if (auto path = FindPhysicalPartition(fs_mgr_get_super_partition_name())) {
David Anderson0f626632018-08-31 16:44:25 -0700159 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 Valsarajudca328d2018-09-24 16:01:35 -0700169
170bool GetDeviceLockStatus() {
171 std::string cmdline;
172 android::base::ReadFileToString("/proc/cmdline", &cmdline);
173 return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
174}