blob: 0157e7fd450e3f604c5d8060194891ed0d6070fc [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
David Anderson12211d12018-07-24 15:21:20 -070024#include <android-base/logging.h>
David Anderson88ef0b12018-08-09 10:40:00 -070025#include <fs_mgr_dm_linear.h>
26#include <liblp/liblp.h>
David Anderson12211d12018-07-24 15:21:20 -070027
28#include "fastboot_device.h"
29
David Anderson88ef0b12018-08-09 10:40:00 -070030using namespace android::fs_mgr;
David Anderson12211d12018-07-24 15:21:20 -070031using android::base::unique_fd;
Hridya Valsaraju31d2c262018-07-20 13:35:50 -070032using android::hardware::boot::V1_0::Slot;
33
David Anderson12211d12018-07-24 15:21:20 -070034static bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
35 std::optional<std::string> path = FindPhysicalPartition(name);
36 if (!path) {
37 return false;
38 }
39 *handle = PartitionHandle(*path);
40 return true;
41}
42
David Anderson88ef0b12018-08-09 10:40:00 -070043static bool OpenLogicalPartition(const std::string& name, const std::string& slot,
44 PartitionHandle* handle) {
45 std::optional<std::string> path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
46 if (!path) {
47 return false;
48 }
49 uint32_t slot_number = SlotNumberForSlotSuffix(slot);
50 std::string dm_path;
51 if (!CreateLogicalPartition(path->c_str(), slot_number, name, true, &dm_path)) {
52 LOG(ERROR) << "Could not map partition: " << name;
53 return false;
54 }
55 auto closer = [name]() -> void { DestroyLogicalPartition(name); };
56 *handle = PartitionHandle(dm_path, std::move(closer));
57 return true;
58}
59
60bool OpenPartition(FastbootDevice* device, const std::string& name, PartitionHandle* handle) {
61 // We prioritize logical partitions over physical ones, and do this
62 // consistently for other partition operations (like getvar:partition-size).
63 if (LogicalPartitionExists(name, device->GetCurrentSlot())) {
64 if (!OpenLogicalPartition(name, device->GetCurrentSlot(), handle)) {
65 return false;
66 }
67 } else if (!OpenPhysicalPartition(name, handle)) {
David Anderson12211d12018-07-24 15:21:20 -070068 LOG(ERROR) << "No such partition: " << name;
69 return false;
70 }
71
72 unique_fd fd(TEMP_FAILURE_RETRY(open(handle->path().c_str(), O_WRONLY | O_EXCL)));
73 if (fd < 0) {
74 PLOG(ERROR) << "Failed to open block device: " << handle->path();
75 return false;
76 }
77 handle->set_fd(std::move(fd));
78 return true;
79}
80
81std::optional<std::string> FindPhysicalPartition(const std::string& name) {
82 std::string path = "/dev/block/by-name/" + name;
83 if (access(path.c_str(), R_OK | W_OK) < 0) {
84 return {};
85 }
86 return path;
87}
88
David Anderson88ef0b12018-08-09 10:40:00 -070089static const LpMetadataPartition* FindLogicalPartition(const LpMetadata& metadata,
90 const std::string& name) {
91 for (const auto& partition : metadata.partitions) {
92 if (GetPartitionName(partition) == name) {
93 return &partition;
94 }
95 }
96 return nullptr;
97}
98
99bool LogicalPartitionExists(const std::string& name, const std::string& slot_suffix,
100 bool* is_zero_length) {
101 auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME);
102 if (!path) {
103 return false;
104 }
105
106 uint32_t slot_number = SlotNumberForSlotSuffix(slot_suffix);
107 std::unique_ptr<LpMetadata> metadata = ReadMetadata(path->c_str(), slot_number);
108 if (!metadata) {
109 return false;
110 }
111 const LpMetadataPartition* partition = FindLogicalPartition(*metadata.get(), name);
112 if (!partition) {
113 return false;
114 }
115 if (is_zero_length) {
116 *is_zero_length = (partition->num_extents == 0);
117 }
118 return true;
119}
120
Hridya Valsaraju31d2c262018-07-20 13:35:50 -0700121bool GetSlotNumber(const std::string& slot, Slot* number) {
122 if (slot.size() != 1) {
123 return false;
124 }
125 if (slot[0] < 'a' || slot[0] > 'z') {
126 return false;
127 }
128 *number = slot[0] - 'a';
129 return true;
130}
David Anderson0f626632018-08-31 16:44:25 -0700131
132std::vector<std::string> ListPartitions(FastbootDevice* device) {
133 std::vector<std::string> partitions;
134
135 // First get physical partitions.
136 struct dirent* de;
137 std::unique_ptr<DIR, decltype(&closedir)> by_name(opendir("/dev/block/by-name"), closedir);
138 while ((de = readdir(by_name.get())) != nullptr) {
139 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
140 continue;
141 }
142 struct stat s;
143 std::string path = "/dev/block/by-name/" + std::string(de->d_name);
144 if (!stat(path.c_str(), &s) && S_ISBLK(s.st_mode)) {
145 partitions.emplace_back(de->d_name);
146 }
147 }
148
149 // Next get logical partitions.
150 if (auto path = FindPhysicalPartition(LP_METADATA_PARTITION_NAME)) {
151 uint32_t slot_number = SlotNumberForSlotSuffix(device->GetCurrentSlot());
152 if (auto metadata = ReadMetadata(path->c_str(), slot_number)) {
153 for (const auto& partition : metadata->partitions) {
154 std::string partition_name = GetPartitionName(partition);
155 partitions.emplace_back(partition_name);
156 }
157 }
158 }
159 return partitions;
160}