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 "libdm/dm.h"
18
19 #include <linux/dm-ioctl.h>
20 #include <sys/ioctl.h>
21 #include <sys/sysmacros.h>
22 #include <sys/types.h>
23 #include <sys/utsname.h>
24
25 #include <chrono>
26 #include <functional>
27 #include <string_view>
28 #include <thread>
29
30 #include <android-base/file.h>
31 #include <android-base/logging.h>
32 #include <android-base/macros.h>
33 #include <android-base/properties.h>
34 #include <android-base/strings.h>
35 #include <uuid/uuid.h>
36
37 #include "utility.h"
38
39 #ifndef DM_DEFERRED_REMOVE
40 #define DM_DEFERRED_REMOVE (1 << 17)
41 #endif
42
43 namespace android {
44 namespace dm {
45
46 using namespace std::literals;
47
DeviceMapper()48 DeviceMapper::DeviceMapper() : fd_(-1) {
49 fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
50 if (fd_ < 0) {
51 PLOG(ERROR) << "Failed to open device-mapper";
52 }
53 }
54
Instance()55 DeviceMapper& DeviceMapper::Instance() {
56 static DeviceMapper instance;
57 return instance;
58 }
59
60 // Creates a new device mapper device
CreateDevice(const std::string & name,const std::string & uuid)61 bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
62 if (name.empty()) {
63 LOG(ERROR) << "Unnamed device mapper device creation is not supported";
64 return false;
65 }
66 if (name.size() >= DM_NAME_LEN) {
67 LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
68 return false;
69 }
70
71 struct dm_ioctl io;
72 InitIo(&io, name);
73 if (!uuid.empty()) {
74 snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
75 }
76
77 if (ioctl(fd_, DM_DEV_CREATE, &io)) {
78 PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
79 return false;
80 }
81
82 // Check to make sure the newly created device doesn't already have targets
83 // added or opened by someone
84 CHECK(io.target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
85 CHECK(io.open_count == 0) << "Unexpected opens for newly created [" << name << "] device";
86
87 // Creates a new device mapper device with the name passed in
88 return true;
89 }
90
DeleteDeviceIfExists(const std::string & name,const std::chrono::milliseconds & timeout_ms)91 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name,
92 const std::chrono::milliseconds& timeout_ms) {
93 if (GetState(name) == DmDeviceState::INVALID) {
94 return true;
95 }
96 return DeleteDevice(name, timeout_ms);
97 }
98
DeleteDeviceIfExists(const std::string & name)99 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name) {
100 return DeleteDeviceIfExists(name, 0ms);
101 }
102
DeleteDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms)103 bool DeviceMapper::DeleteDevice(const std::string& name,
104 const std::chrono::milliseconds& timeout_ms) {
105 std::string unique_path;
106 if (!GetDeviceUniquePath(name, &unique_path)) {
107 LOG(ERROR) << "Failed to get unique path for device " << name;
108 }
109 struct dm_ioctl io;
110 InitIo(&io, name);
111
112 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
113 PLOG(ERROR) << "DM_DEV_REMOVE failed for [" << name << "]";
114 return false;
115 }
116
117 // Check to make sure appropriate uevent is generated so ueventd will
118 // do the right thing and remove the corresponding device node and symlinks.
119 if ((io.flags & DM_UEVENT_GENERATED_FLAG) == 0) {
120 LOG(ERROR) << "Didn't generate uevent for [" << name << "] removal";
121 return false;
122 }
123
124 if (timeout_ms <= std::chrono::milliseconds::zero()) {
125 return true;
126 }
127 if (unique_path.empty()) {
128 return false;
129 }
130 if (!WaitForFileDeleted(unique_path, timeout_ms)) {
131 LOG(ERROR) << "Failed waiting for " << unique_path << " to be deleted";
132 return false;
133 }
134 return true;
135 }
136
DeleteDevice(const std::string & name)137 bool DeviceMapper::DeleteDevice(const std::string& name) {
138 return DeleteDevice(name, 0ms);
139 }
140
DeleteDeviceDeferred(const std::string & name)141 bool DeviceMapper::DeleteDeviceDeferred(const std::string& name) {
142 struct dm_ioctl io;
143 InitIo(&io, name);
144
145 io.flags |= DM_DEFERRED_REMOVE;
146 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
147 PLOG(ERROR) << "DM_DEV_REMOVE with DM_DEFERRED_REMOVE failed for [" << name << "]";
148 return false;
149 }
150 return true;
151 }
152
DeleteDeviceIfExistsDeferred(const std::string & name)153 bool DeviceMapper::DeleteDeviceIfExistsDeferred(const std::string& name) {
154 if (GetState(name) == DmDeviceState::INVALID) {
155 return true;
156 }
157 return DeleteDeviceDeferred(name);
158 }
159
GenerateUuid()160 static std::string GenerateUuid() {
161 uuid_t uuid_bytes;
162 uuid_generate(uuid_bytes);
163
164 char uuid_chars[37] = {};
165 uuid_unparse_lower(uuid_bytes, uuid_chars);
166
167 return std::string{uuid_chars};
168 }
169
IsRecovery()170 static bool IsRecovery() {
171 return access("/system/bin/recovery", F_OK) == 0;
172 }
173
CreateEmptyDevice(const std::string & name)174 bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
175 std::string uuid = GenerateUuid();
176 return CreateDevice(name, uuid);
177 }
178
WaitForDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms,std::string * path)179 bool DeviceMapper::WaitForDevice(const std::string& name,
180 const std::chrono::milliseconds& timeout_ms, std::string* path) {
181 // We use the unique path for testing whether the device is ready. After
182 // that, it's safe to use the dm-N path which is compatible with callers
183 // that expect it to be formatted as such.
184 std::string unique_path;
185 if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
186 DeleteDevice(name);
187 return false;
188 }
189
190 if (timeout_ms <= std::chrono::milliseconds::zero()) {
191 return true;
192 }
193
194 if (IsRecovery()) {
195 bool non_ab_device = android::base::GetProperty("ro.build.ab_update", "").empty();
196 int sdk = android::base::GetIntProperty("ro.build.version.sdk", 0);
197 if (non_ab_device && sdk && sdk <= 29) {
198 LOG(INFO) << "Detected ueventd incompatibility, reverting to legacy libdm behavior.";
199 unique_path = *path;
200 }
201 }
202
203 if (!WaitForFile(unique_path, timeout_ms)) {
204 LOG(ERROR) << "Failed waiting for device path: " << unique_path;
205 DeleteDevice(name);
206 return false;
207 }
208 return true;
209 }
210
CreateDevice(const std::string & name,const DmTable & table,std::string * path,const std::chrono::milliseconds & timeout_ms)211 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
212 const std::chrono::milliseconds& timeout_ms) {
213 if (!CreateEmptyDevice(name)) {
214 return false;
215 }
216
217 if (!LoadTableAndActivate(name, table)) {
218 DeleteDevice(name);
219 return false;
220 }
221
222 if (!WaitForDevice(name, timeout_ms, path)) {
223 DeleteDevice(name);
224 return false;
225 }
226
227 return true;
228 }
229
GetDeviceUniquePath(const std::string & name,std::string * path)230 bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
231 struct dm_ioctl io;
232 InitIo(&io, name);
233 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
234 PLOG(ERROR) << "Failed to get device path: " << name;
235 return false;
236 }
237
238 if (io.uuid[0] == '\0') {
239 LOG(ERROR) << "Device does not have a unique path: " << name;
240 return false;
241 }
242 *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
243 return true;
244 }
245
GetDeviceNameAndUuid(dev_t dev,std::string * name,std::string * uuid)246 bool DeviceMapper::GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid) {
247 struct dm_ioctl io;
248 InitIo(&io, {});
249 io.dev = dev;
250
251 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
252 PLOG(ERROR) << "Failed to find device dev: " << major(dev) << ":" << minor(dev);
253 return false;
254 }
255
256 if (name) {
257 *name = io.name;
258 }
259 if (uuid) {
260 *uuid = io.uuid;
261 }
262 return true;
263 }
264
GetDetailedInfo(const std::string & name) const265 std::optional<DeviceMapper::Info> DeviceMapper::GetDetailedInfo(const std::string& name) const {
266 struct dm_ioctl io;
267 InitIo(&io, name);
268 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
269 return std::nullopt;
270 }
271 return Info(io.flags);
272 }
273
GetState(const std::string & name) const274 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
275 struct dm_ioctl io;
276 InitIo(&io, name);
277 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
278 return DmDeviceState::INVALID;
279 }
280 if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
281 return DmDeviceState::ACTIVE;
282 }
283 return DmDeviceState::SUSPENDED;
284 }
285
ChangeState(const std::string & name,DmDeviceState state)286 bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) {
287 if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) {
288 return false;
289 }
290
291 struct dm_ioctl io;
292 InitIo(&io, name);
293
294 if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG;
295
296 if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) {
297 PLOG(ERROR) << "DM_DEV_SUSPEND "
298 << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed";
299 return false;
300 }
301 return true;
302 }
303
CreateDevice(const std::string & name,const DmTable & table)304 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
305 std::string ignore_path;
306 if (!CreateDevice(name, table, &ignore_path, 0ms)) {
307 return false;
308 }
309 return true;
310 }
311
LoadTable(const std::string & name,const DmTable & table)312 bool DeviceMapper::LoadTable(const std::string& name, const DmTable& table) {
313 std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
314 ioctl_buffer += table.Serialize();
315
316 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
317 InitIo(io, name);
318 io->data_size = ioctl_buffer.size();
319 io->data_start = sizeof(struct dm_ioctl);
320 io->target_count = static_cast<uint32_t>(table.num_targets());
321 if (table.readonly()) {
322 io->flags |= DM_READONLY_FLAG;
323 }
324 if (ioctl(fd_, DM_TABLE_LOAD, io)) {
325 PLOG(ERROR) << "DM_TABLE_LOAD failed";
326 return false;
327 }
328 return true;
329 }
330
LoadTableAndActivate(const std::string & name,const DmTable & table)331 bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
332 if (!LoadTable(name, table)) {
333 return false;
334 }
335
336 struct dm_ioctl io;
337 InitIo(&io, name);
338 if (ioctl(fd_, DM_DEV_SUSPEND, &io)) {
339 PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
340 return false;
341 }
342 return true;
343 }
344
345 // Reads all the available device mapper targets and their corresponding
346 // versions from the kernel and returns in a vector
GetAvailableTargets(std::vector<DmTargetTypeInfo> * targets)347 bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
348 targets->clear();
349
350 // calculate the space needed to read a maximum of kMaxPossibleDmTargets
351 uint32_t payload_size = sizeof(struct dm_target_versions);
352 payload_size += DM_MAX_TYPE_NAME;
353 // device mapper wants every target spec to be aligned at 8-byte boundary
354 payload_size = DM_ALIGN(payload_size);
355 payload_size *= kMaxPossibleDmTargets;
356
357 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
358 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
359 if (buffer == nullptr) {
360 LOG(ERROR) << "failed to allocate memory";
361 return false;
362 }
363
364 // Sets appropriate data size and data_start to make sure we tell kernel
365 // about the total size of the buffer we are passing and where to start
366 // writing the list of targets.
367 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
368 InitIo(io);
369 io->data_size = data_size;
370 io->data_start = sizeof(*io);
371
372 if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
373 PLOG(ERROR) << "DM_LIST_VERSIONS failed";
374 return false;
375 }
376
377 // If the provided buffer wasn't enough to list all targets, note that
378 // any data beyond sizeof(*io) must not be read in this case
379 if (io->flags & DM_BUFFER_FULL_FLAG) {
380 LOG(INFO) << data_size << " is not enough memory to list all dm targets";
381 return false;
382 }
383
384 // if there are no targets registered, return success with empty vector
385 if (io->data_size == sizeof(*io)) {
386 return true;
387 }
388
389 // Parse each target and list the name and version
390 // TODO(b/110035986): Templatize this
391 uint32_t next = sizeof(*io);
392 data_size = io->data_size - next;
393 struct dm_target_versions* vers =
394 reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
395 while (next && data_size) {
396 targets->emplace_back(vers);
397 if (vers->next == 0) {
398 break;
399 }
400 next += vers->next;
401 data_size -= vers->next;
402 vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
403 next);
404 }
405
406 return true;
407 }
408
GetTargetByName(const std::string & name,DmTargetTypeInfo * info)409 bool DeviceMapper::GetTargetByName(const std::string& name, DmTargetTypeInfo* info) {
410 std::vector<DmTargetTypeInfo> targets;
411 if (!GetAvailableTargets(&targets)) {
412 return false;
413 }
414 for (const auto& target : targets) {
415 if (target.name() == name) {
416 if (info) *info = target;
417 return true;
418 }
419 }
420 return false;
421 }
422
GetAvailableDevices(std::vector<DmBlockDevice> * devices)423 bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
424 devices->clear();
425
426 // calculate the space needed to read a maximum of 256 targets, each with
427 // name with maximum length of 16 bytes
428 uint32_t payload_size = sizeof(struct dm_name_list);
429 // 128-bytes for the name
430 payload_size += DM_NAME_LEN;
431 // dm wants every device spec to be aligned at 8-byte boundary
432 payload_size = DM_ALIGN(payload_size);
433 payload_size *= kMaxPossibleDmDevices;
434 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
435 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
436 if (buffer == nullptr) {
437 LOG(ERROR) << "failed to allocate memory";
438 return false;
439 }
440
441 // Sets appropriate data size and data_start to make sure we tell kernel
442 // about the total size of the buffer we are passing and where to start
443 // writing the list of targets.
444 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
445 InitIo(io);
446 io->data_size = data_size;
447 io->data_start = sizeof(*io);
448
449 if (ioctl(fd_, DM_LIST_DEVICES, io)) {
450 PLOG(ERROR) << "DM_LIST_DEVICES failed";
451 return false;
452 }
453
454 // If the provided buffer wasn't enough to list all devices any data
455 // beyond sizeof(*io) must not be read.
456 if (io->flags & DM_BUFFER_FULL_FLAG) {
457 LOG(INFO) << data_size << " is not enough memory to list all dm devices";
458 return false;
459 }
460
461 // if there are no devices created yet, return success with empty vector
462 if (io->data_size == sizeof(*io)) {
463 return true;
464 }
465
466 // Parse each device and add a new DmBlockDevice to the vector
467 // created from the kernel data.
468 uint32_t next = sizeof(*io);
469 data_size = io->data_size - next;
470 struct dm_name_list* dm_dev =
471 reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
472
473 while (next && data_size) {
474 devices->emplace_back((dm_dev));
475 if (dm_dev->next == 0) {
476 break;
477 }
478 next += dm_dev->next;
479 data_size -= dm_dev->next;
480 dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
481 }
482
483 return true;
484 }
485
486 // Accepts a device mapper device name (like system_a, vendor_b etc) and
487 // returns the path to it's device node (or symlink to the device node)
GetDmDevicePathByName(const std::string & name,std::string * path)488 bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
489 struct dm_ioctl io;
490 InitIo(&io, name);
491 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
492 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
493 return false;
494 }
495
496 uint32_t dev_num = minor(io.dev);
497 *path = "/dev/block/dm-" + std::to_string(dev_num);
498 return true;
499 }
500
501 // Accepts a device mapper device name (like system_a, vendor_b etc) and
502 // returns its UUID.
GetDmDeviceUuidByName(const std::string & name,std::string * uuid)503 bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
504 struct dm_ioctl io;
505 InitIo(&io, name);
506 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
507 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
508 return false;
509 }
510
511 *uuid = std::string(io.uuid);
512 return true;
513 }
514
GetDeviceNumber(const std::string & name,dev_t * dev)515 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
516 struct dm_ioctl io;
517 InitIo(&io, name);
518 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
519 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
520 return false;
521 }
522 *dev = io.dev;
523 return true;
524 }
525
GetDeviceString(const std::string & name,std::string * dev)526 bool DeviceMapper::GetDeviceString(const std::string& name, std::string* dev) {
527 dev_t num;
528 if (!GetDeviceNumber(name, &num)) {
529 return false;
530 }
531 *dev = std::to_string(major(num)) + ":" + std::to_string(minor(num));
532 return true;
533 }
534
GetTableStatus(const std::string & name,std::vector<TargetInfo> * table)535 bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
536 return GetTable(name, 0, table);
537 }
538
GetTableInfo(const std::string & name,std::vector<TargetInfo> * table)539 bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
540 return GetTable(name, DM_STATUS_TABLE_FLAG, table);
541 }
542
543 // private methods of DeviceMapper
GetTable(const std::string & name,uint32_t flags,std::vector<TargetInfo> * table)544 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
545 std::vector<TargetInfo>* table) {
546 std::vector<char> buffer;
547 struct dm_ioctl* io = nullptr;
548
549 for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
550 io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
551
552 InitIo(io, name);
553 io->data_size = buffer.size();
554 io->data_start = sizeof(*io);
555 io->flags = flags;
556 if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
557 PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
558 return false;
559 }
560 if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
561 }
562
563 uint32_t cursor = io->data_start;
564 uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
565 for (uint32_t i = 0; i < io->target_count; i++) {
566 if (cursor + sizeof(struct dm_target_spec) > data_end) {
567 break;
568 }
569 // After each dm_target_spec is a status string. spec->next is an
570 // offset from |io->data_start|, and we clamp it to the size of our
571 // buffer.
572 struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
573 uint32_t data_offset = cursor + sizeof(dm_target_spec);
574 uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
575
576 std::string data;
577 if (next_cursor > data_offset) {
578 // Note: we use c_str() to eliminate any extra trailing 0s.
579 data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
580 }
581 table->emplace_back(*spec, data);
582 cursor = next_cursor;
583 }
584 return true;
585 }
586
InitIo(struct dm_ioctl * io,const std::string & name) const587 void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
588 CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
589 memset(io, 0, sizeof(*io));
590
591 io->version[0] = DM_VERSION0;
592 io->version[1] = DM_VERSION1;
593 io->version[2] = DM_VERSION2;
594 io->data_size = sizeof(*io);
595 io->data_start = 0;
596 if (!name.empty()) {
597 snprintf(io->name, sizeof(io->name), "%s", name.c_str());
598 }
599 }
600
GetTargetType(const struct dm_target_spec & spec)601 std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
602 if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
603 ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
604 return std::string{spec.target_type, static_cast<size_t>(length)};
605 }
606 return std::string{spec.target_type, sizeof(spec.target_type)};
607 }
608
ExtractBlockDeviceName(const std::string & path)609 std::optional<std::string> ExtractBlockDeviceName(const std::string& path) {
610 static constexpr std::string_view kDevBlockPrefix("/dev/block/");
611 if (android::base::StartsWith(path, kDevBlockPrefix)) {
612 return path.substr(kDevBlockPrefix.length());
613 }
614 return {};
615 }
616
IsDmBlockDevice(const std::string & path)617 bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
618 std::optional<std::string> name = ExtractBlockDeviceName(path);
619 return name && android::base::StartsWith(*name, "dm-");
620 }
621
GetDmDeviceNameByPath(const std::string & path)622 std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
623 std::optional<std::string> name = ExtractBlockDeviceName(path);
624 if (!name) {
625 LOG(WARNING) << path << " is not a block device";
626 return std::nullopt;
627 }
628 if (!android::base::StartsWith(*name, "dm-")) {
629 LOG(WARNING) << path << " is not a dm device";
630 return std::nullopt;
631 }
632 std::string dm_name_file = "/sys/block/" + *name + "/dm/name";
633 std::string dm_name;
634 if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
635 PLOG(ERROR) << "Failed to read file " << dm_name_file;
636 return std::nullopt;
637 }
638 dm_name = android::base::Trim(dm_name);
639 return dm_name;
640 }
641
GetParentBlockDeviceByPath(const std::string & path)642 std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
643 std::optional<std::string> name = ExtractBlockDeviceName(path);
644 if (!name) {
645 LOG(WARNING) << path << " is not a block device";
646 return std::nullopt;
647 }
648 if (!android::base::StartsWith(*name, "dm-")) {
649 // Reached bottom of the device mapper stack.
650 return std::nullopt;
651 }
652 auto slaves_dir = "/sys/block/" + *name + "/slaves";
653 auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
654 if (dir == nullptr) {
655 PLOG(ERROR) << "Failed to open: " << slaves_dir;
656 return std::nullopt;
657 }
658 std::string sub_device_name = "";
659 for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
660 if (entry->d_type != DT_LNK) continue;
661 if (!sub_device_name.empty()) {
662 LOG(ERROR) << "Too many slaves in " << slaves_dir;
663 return std::nullopt;
664 }
665 sub_device_name = entry->d_name;
666 }
667 if (sub_device_name.empty()) {
668 LOG(ERROR) << "No slaves in " << slaves_dir;
669 return std::nullopt;
670 }
671 return "/dev/block/" + sub_device_name;
672 }
673
IsOverflowSnapshot() const674 bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
675 return spec.target_type == "snapshot"s && data == "Overflow"s;
676 }
677
678 // Find directories in format of "/sys/block/dm-X".
DmNameFilter(const dirent * de)679 static int DmNameFilter(const dirent* de) {
680 if (android::base::StartsWith(de->d_name, "dm-")) {
681 return 1;
682 }
683 return 0;
684 }
685
FindDmPartitions()686 std::map<std::string, std::string> DeviceMapper::FindDmPartitions() {
687 static constexpr auto DM_PATH_PREFIX = "/sys/block/";
688 dirent** namelist;
689 int n = scandir(DM_PATH_PREFIX, &namelist, DmNameFilter, alphasort);
690 if (n == -1) {
691 PLOG(ERROR) << "Failed to scan dir " << DM_PATH_PREFIX;
692 return {};
693 }
694 if (n == 0) {
695 LOG(ERROR) << "No dm block device found.";
696 free(namelist);
697 return {};
698 }
699
700 static constexpr auto DM_PATH_SUFFIX = "/dm/name";
701 static constexpr auto DEV_PATH = "/dev/block/";
702 std::map<std::string, std::string> dm_block_devices;
703 while (n--) {
704 std::string path = DM_PATH_PREFIX + std::string(namelist[n]->d_name) + DM_PATH_SUFFIX;
705 std::string content;
706 if (!android::base::ReadFileToString(path, &content)) {
707 PLOG(WARNING) << "Failed to read " << path;
708 } else {
709 std::string dm_block_name = android::base::Trim(content);
710 // AVB is using 'vroot' for the root block device but we're expecting 'system'.
711 if (dm_block_name == "vroot") {
712 dm_block_name = "system";
713 } else if (android::base::EndsWith(dm_block_name, "-verity")) {
714 auto npos = dm_block_name.rfind("-verity");
715 dm_block_name = dm_block_name.substr(0, npos);
716 } else if (!android::base::GetProperty("ro.boot.avb_version", "").empty()) {
717 // Verified Boot 1.0 doesn't add a -verity suffix. On AVB 2 devices,
718 // if DAP is enabled, then a -verity suffix must be used to
719 // differentiate between dm-linear and dm-verity devices. If we get
720 // here, we're AVB 2 and looking at a non-verity partition.
721 free(namelist[n]);
722 continue;
723 }
724
725 dm_block_devices.emplace(dm_block_name, DEV_PATH + std::string(namelist[n]->d_name));
726 }
727 free(namelist[n]);
728 }
729 free(namelist);
730
731 return dm_block_devices;
732 }
733
CreatePlaceholderDevice(const std::string & name)734 bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) {
735 if (!CreateEmptyDevice(name)) {
736 return false;
737 }
738
739 struct utsname uts;
740 unsigned int major, minor;
741 if (uname(&uts) != 0 || sscanf(uts.release, "%u.%u", &major, &minor) != 2) {
742 LOG(ERROR) << "Could not parse the kernel version from uname";
743 return true;
744 }
745
746 // On Linux 5.15+, there is no uevent until DM_TABLE_LOAD.
747 if (major > 5 || (major == 5 && minor >= 15)) {
748 DmTable table;
749 table.Emplace<DmTargetError>(0, 1);
750 if (!LoadTable(name, table)) {
751 return false;
752 }
753 }
754 return true;
755 }
756
757 } // namespace dm
758 } // namespace android
759