• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
19 #include <dirent.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/properties.h>
27 #include <android-base/strings.h>
28 #include <fs_mgr.h>
29 #include <fs_mgr_dm_linear.h>
30 #include <liblp/builder.h>
31 #include <liblp/liblp.h>
32 
33 #include "fastboot_device.h"
34 
35 using namespace android::fs_mgr;
36 using namespace std::chrono_literals;
37 using android::base::unique_fd;
38 using android::hardware::boot::V1_0::Slot;
39 
40 namespace {
41 
OpenPhysicalPartition(const std::string & name,PartitionHandle * handle)42 bool OpenPhysicalPartition(const std::string& name, PartitionHandle* handle) {
43     std::optional<std::string> path = FindPhysicalPartition(name);
44     if (!path) {
45         return false;
46     }
47     *handle = PartitionHandle(*path);
48     return true;
49 }
50 
OpenLogicalPartition(FastbootDevice * device,const std::string & partition_name,PartitionHandle * handle)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));
56     if (!path) {
57         return false;
58     }
59     std::string dm_path;
60     if (!CreateLogicalPartition(path->c_str(), slot_number, partition_name, true, 5s, &dm_path)) {
61         LOG(ERROR) << "Could not map partition: " << partition_name;
62         return false;
63     }
64     auto closer = [partition_name]() -> void { DestroyLogicalPartition(partition_name, 5s); };
65     *handle = PartitionHandle(dm_path, std::move(closer));
66     return true;
67 }
68 
69 }  // namespace
70 
OpenPartition(FastbootDevice * device,const std::string & name,PartitionHandle * handle)71 bool 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).
74     if (LogicalPartitionExists(device, name)) {
75         if (!OpenLogicalPartition(device, name, handle)) {
76             return false;
77         }
78     } else if (!OpenPhysicalPartition(name, handle)) {
79         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 
FindPhysicalPartition(const std::string & name)92 std::optional<std::string> FindPhysicalPartition(const std::string& name) {
93     // Check for an invalid file name
94     if (android::base::StartsWith(name, "../") || name.find("/../") != std::string::npos) {
95         return {};
96     }
97     std::string path = "/dev/block/by-name/" + name;
98     if (access(path.c_str(), W_OK) < 0) {
99         return {};
100     }
101     return path;
102 }
103 
FindLogicalPartition(const LpMetadata & metadata,const std::string & name)104 static 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 
LogicalPartitionExists(FastbootDevice * device,const std::string & name,bool * is_zero_length)114 bool 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));
118     if (!path) {
119         return false;
120     }
121 
122     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 
GetSlotNumber(const std::string & slot,Slot * number)136 bool 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 }
146 
ListPartitions(FastbootDevice * device)147 std::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 
164     // 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()) {
187                 partitions.emplace_back(partition_name);
188             }
189         }
190     }
191     return partitions;
192 }
193 
GetDeviceLockStatus()194 bool GetDeviceLockStatus() {
195     std::string cmdline;
196     // Return lock status true if unable to read kernel command line.
197     if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
198         return true;
199     }
200     return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos;
201 }
202 
UpdateAllPartitionMetadata(FastbootDevice * device,const std::string & super_name,const android::fs_mgr::LpMetadata & metadata)203 bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name,
204                                 const android::fs_mgr::LpMetadata& metadata) {
205     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 
211     bool ok = true;
212     for (size_t i = 0; i < num_slots; i++) {
213         ok &= UpdatePartitionTable(super_name, metadata, i);
214     }
215     return ok;
216 }
217 
GetSuperSlotSuffix(FastbootDevice * device,const std::string & partition_name)218 std::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 }
235