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
24 #include <chrono>
25 #include <functional>
26 #include <string_view>
27 #include <thread>
28
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/macros.h>
32 #include <android-base/properties.h>
33 #include <android-base/strings.h>
34 #include <uuid/uuid.h>
35
36 #include "utility.h"
37
38 #ifndef DM_DEFERRED_REMOVE
39 #define DM_DEFERRED_REMOVE (1 << 17)
40 #endif
41
42 namespace android {
43 namespace dm {
44
45 using namespace std::literals;
46
DeviceMapper()47 DeviceMapper::DeviceMapper() : fd_(-1) {
48 fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
49 if (fd_ < 0) {
50 PLOG(ERROR) << "Failed to open device-mapper";
51 }
52 }
53
Instance()54 DeviceMapper& DeviceMapper::Instance() {
55 static DeviceMapper instance;
56 return instance;
57 }
58
59 // Creates a new device mapper device
CreateDevice(const std::string & name,const std::string & uuid)60 bool DeviceMapper::CreateDevice(const std::string& name, const std::string& uuid) {
61 if (name.empty()) {
62 LOG(ERROR) << "Unnamed device mapper device creation is not supported";
63 return false;
64 }
65 if (name.size() >= DM_NAME_LEN) {
66 LOG(ERROR) << "[" << name << "] is too long to be device mapper name";
67 return false;
68 }
69
70 struct dm_ioctl io;
71 InitIo(&io, name);
72 if (!uuid.empty()) {
73 snprintf(io.uuid, sizeof(io.uuid), "%s", uuid.c_str());
74 }
75
76 if (ioctl(fd_, DM_DEV_CREATE, &io)) {
77 PLOG(ERROR) << "DM_DEV_CREATE failed for [" << name << "]";
78 return false;
79 }
80
81 // Check to make sure the newly created device doesn't already have targets
82 // added or opened by someone
83 CHECK(io.target_count == 0) << "Unexpected targets for newly created [" << name << "] device";
84 CHECK(io.open_count == 0) << "Unexpected opens for newly created [" << name << "] device";
85
86 // Creates a new device mapper device with the name passed in
87 return true;
88 }
89
DeleteDeviceIfExists(const std::string & name,const std::chrono::milliseconds & timeout_ms)90 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name,
91 const std::chrono::milliseconds& timeout_ms) {
92 if (GetState(name) == DmDeviceState::INVALID) {
93 return true;
94 }
95 return DeleteDevice(name, timeout_ms);
96 }
97
DeleteDeviceIfExists(const std::string & name)98 bool DeviceMapper::DeleteDeviceIfExists(const std::string& name) {
99 return DeleteDeviceIfExists(name, 0ms);
100 }
101
DeleteDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms)102 bool DeviceMapper::DeleteDevice(const std::string& name,
103 const std::chrono::milliseconds& timeout_ms) {
104 std::string unique_path;
105 if (!GetDeviceUniquePath(name, &unique_path)) {
106 LOG(ERROR) << "Failed to get unique path for device " << name;
107 }
108 struct dm_ioctl io;
109 InitIo(&io, name);
110
111 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
112 PLOG(ERROR) << "DM_DEV_REMOVE failed for [" << name << "]";
113 return false;
114 }
115
116 // Check to make sure appropriate uevent is generated so ueventd will
117 // do the right thing and remove the corresponding device node and symlinks.
118 if ((io.flags & DM_UEVENT_GENERATED_FLAG) == 0) {
119 LOG(ERROR) << "Didn't generate uevent for [" << name << "] removal";
120 return false;
121 }
122
123 if (timeout_ms <= std::chrono::milliseconds::zero()) {
124 return true;
125 }
126 if (unique_path.empty()) {
127 return false;
128 }
129 if (!WaitForFileDeleted(unique_path, timeout_ms)) {
130 LOG(ERROR) << "Failed waiting for " << unique_path << " to be deleted";
131 return false;
132 }
133 return true;
134 }
135
DeleteDevice(const std::string & name)136 bool DeviceMapper::DeleteDevice(const std::string& name) {
137 return DeleteDevice(name, 0ms);
138 }
139
DeleteDeviceDeferred(const std::string & name)140 bool DeviceMapper::DeleteDeviceDeferred(const std::string& name) {
141 struct dm_ioctl io;
142 InitIo(&io, name);
143
144 io.flags |= DM_DEFERRED_REMOVE;
145 if (ioctl(fd_, DM_DEV_REMOVE, &io)) {
146 PLOG(ERROR) << "DM_DEV_REMOVE with DM_DEFERRED_REMOVE failed for [" << name << "]";
147 return false;
148 }
149 return true;
150 }
151
DeleteDeviceIfExistsDeferred(const std::string & name)152 bool DeviceMapper::DeleteDeviceIfExistsDeferred(const std::string& name) {
153 if (GetState(name) == DmDeviceState::INVALID) {
154 return true;
155 }
156 return DeleteDeviceDeferred(name);
157 }
158
GenerateUuid()159 static std::string GenerateUuid() {
160 uuid_t uuid_bytes;
161 uuid_generate(uuid_bytes);
162
163 char uuid_chars[37] = {};
164 uuid_unparse_lower(uuid_bytes, uuid_chars);
165
166 return std::string{uuid_chars};
167 }
168
IsRecovery()169 static bool IsRecovery() {
170 return access("/system/bin/recovery", F_OK) == 0;
171 }
172
CreateDevice(const std::string & name,const DmTable & table,std::string * path,const std::chrono::milliseconds & timeout_ms)173 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
174 const std::chrono::milliseconds& timeout_ms) {
175 std::string uuid = GenerateUuid();
176 if (!CreateDevice(name, uuid)) {
177 return false;
178 }
179
180 // We use the unique path for testing whether the device is ready. After
181 // that, it's safe to use the dm-N path which is compatible with callers
182 // that expect it to be formatted as such.
183 std::string unique_path;
184 if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) ||
185 !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
GetDeviceUniquePath(const std::string & name,std::string * path)211 bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
212 struct dm_ioctl io;
213 InitIo(&io, name);
214 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
215 PLOG(ERROR) << "Failed to get device path: " << name;
216 return false;
217 }
218
219 if (io.uuid[0] == '\0') {
220 LOG(ERROR) << "Device does not have a unique path: " << name;
221 return false;
222 }
223 *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
224 return true;
225 }
226
GetDetailedInfo(const std::string & name) const227 std::optional<DeviceMapper::Info> DeviceMapper::GetDetailedInfo(const std::string& name) const {
228 struct dm_ioctl io;
229 InitIo(&io, name);
230 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
231 return std::nullopt;
232 }
233 return Info(io.flags);
234 }
235
GetState(const std::string & name) const236 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
237 struct dm_ioctl io;
238 InitIo(&io, name);
239 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
240 return DmDeviceState::INVALID;
241 }
242 if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
243 return DmDeviceState::ACTIVE;
244 }
245 return DmDeviceState::SUSPENDED;
246 }
247
ChangeState(const std::string & name,DmDeviceState state)248 bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) {
249 if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) {
250 return false;
251 }
252
253 struct dm_ioctl io;
254 InitIo(&io, name);
255
256 if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG;
257
258 if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) {
259 PLOG(ERROR) << "DM_DEV_SUSPEND "
260 << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed";
261 return false;
262 }
263 return true;
264 }
265
CreateDevice(const std::string & name,const DmTable & table)266 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
267 std::string ignore_path;
268 if (!CreateDevice(name, table, &ignore_path, 0ms)) {
269 return false;
270 }
271 return true;
272 }
273
LoadTableAndActivate(const std::string & name,const DmTable & table)274 bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
275 std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
276 ioctl_buffer += table.Serialize();
277
278 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
279 InitIo(io, name);
280 io->data_size = ioctl_buffer.size();
281 io->data_start = sizeof(struct dm_ioctl);
282 io->target_count = static_cast<uint32_t>(table.num_targets());
283 if (table.readonly()) {
284 io->flags |= DM_READONLY_FLAG;
285 }
286 if (ioctl(fd_, DM_TABLE_LOAD, io)) {
287 PLOG(ERROR) << "DM_TABLE_LOAD failed";
288 return false;
289 }
290
291 InitIo(io, name);
292 if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
293 PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
294 return false;
295 }
296 return true;
297 }
298
299 // Reads all the available device mapper targets and their corresponding
300 // versions from the kernel and returns in a vector
GetAvailableTargets(std::vector<DmTargetTypeInfo> * targets)301 bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
302 targets->clear();
303
304 // calculate the space needed to read a maximum of kMaxPossibleDmTargets
305 uint32_t payload_size = sizeof(struct dm_target_versions);
306 payload_size += DM_MAX_TYPE_NAME;
307 // device mapper wants every target spec to be aligned at 8-byte boundary
308 payload_size = DM_ALIGN(payload_size);
309 payload_size *= kMaxPossibleDmTargets;
310
311 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
312 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
313 if (buffer == nullptr) {
314 LOG(ERROR) << "failed to allocate memory";
315 return false;
316 }
317
318 // Sets appropriate data size and data_start to make sure we tell kernel
319 // about the total size of the buffer we are passing and where to start
320 // writing the list of targets.
321 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
322 InitIo(io);
323 io->data_size = data_size;
324 io->data_start = sizeof(*io);
325
326 if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
327 PLOG(ERROR) << "DM_LIST_VERSIONS failed";
328 return false;
329 }
330
331 // If the provided buffer wasn't enough to list all targets, note that
332 // any data beyond sizeof(*io) must not be read in this case
333 if (io->flags & DM_BUFFER_FULL_FLAG) {
334 LOG(INFO) << data_size << " is not enough memory to list all dm targets";
335 return false;
336 }
337
338 // if there are no targets registered, return success with empty vector
339 if (io->data_size == sizeof(*io)) {
340 return true;
341 }
342
343 // Parse each target and list the name and version
344 // TODO(b/110035986): Templatize this
345 uint32_t next = sizeof(*io);
346 data_size = io->data_size - next;
347 struct dm_target_versions* vers =
348 reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
349 while (next && data_size) {
350 targets->emplace_back(vers);
351 if (vers->next == 0) {
352 break;
353 }
354 next += vers->next;
355 data_size -= vers->next;
356 vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
357 next);
358 }
359
360 return true;
361 }
362
GetTargetByName(const std::string & name,DmTargetTypeInfo * info)363 bool DeviceMapper::GetTargetByName(const std::string& name, DmTargetTypeInfo* info) {
364 std::vector<DmTargetTypeInfo> targets;
365 if (!GetAvailableTargets(&targets)) {
366 return false;
367 }
368 for (const auto& target : targets) {
369 if (target.name() == name) {
370 if (info) *info = target;
371 return true;
372 }
373 }
374 return false;
375 }
376
GetAvailableDevices(std::vector<DmBlockDevice> * devices)377 bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
378 devices->clear();
379
380 // calculate the space needed to read a maximum of 256 targets, each with
381 // name with maximum length of 16 bytes
382 uint32_t payload_size = sizeof(struct dm_name_list);
383 // 128-bytes for the name
384 payload_size += DM_NAME_LEN;
385 // dm wants every device spec to be aligned at 8-byte boundary
386 payload_size = DM_ALIGN(payload_size);
387 payload_size *= kMaxPossibleDmDevices;
388 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
389 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
390 if (buffer == nullptr) {
391 LOG(ERROR) << "failed to allocate memory";
392 return false;
393 }
394
395 // Sets appropriate data size and data_start to make sure we tell kernel
396 // about the total size of the buffer we are passing and where to start
397 // writing the list of targets.
398 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
399 InitIo(io);
400 io->data_size = data_size;
401 io->data_start = sizeof(*io);
402
403 if (ioctl(fd_, DM_LIST_DEVICES, io)) {
404 PLOG(ERROR) << "DM_LIST_DEVICES failed";
405 return false;
406 }
407
408 // If the provided buffer wasn't enough to list all devices any data
409 // beyond sizeof(*io) must not be read.
410 if (io->flags & DM_BUFFER_FULL_FLAG) {
411 LOG(INFO) << data_size << " is not enough memory to list all dm devices";
412 return false;
413 }
414
415 // if there are no devices created yet, return success with empty vector
416 if (io->data_size == sizeof(*io)) {
417 return true;
418 }
419
420 // Parse each device and add a new DmBlockDevice to the vector
421 // created from the kernel data.
422 uint32_t next = sizeof(*io);
423 data_size = io->data_size - next;
424 struct dm_name_list* dm_dev =
425 reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
426
427 while (next && data_size) {
428 devices->emplace_back((dm_dev));
429 if (dm_dev->next == 0) {
430 break;
431 }
432 next += dm_dev->next;
433 data_size -= dm_dev->next;
434 dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
435 }
436
437 return true;
438 }
439
440 // Accepts a device mapper device name (like system_a, vendor_b etc) and
441 // returns the path to it's device node (or symlink to the device node)
GetDmDevicePathByName(const std::string & name,std::string * path)442 bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
443 struct dm_ioctl io;
444 InitIo(&io, name);
445 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
446 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
447 return false;
448 }
449
450 uint32_t dev_num = minor(io.dev);
451 *path = "/dev/block/dm-" + std::to_string(dev_num);
452 return true;
453 }
454
455 // Accepts a device mapper device name (like system_a, vendor_b etc) and
456 // returns its UUID.
GetDmDeviceUuidByName(const std::string & name,std::string * uuid)457 bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
458 struct dm_ioctl io;
459 InitIo(&io, name);
460 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
461 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
462 return false;
463 }
464
465 *uuid = std::string(io.uuid);
466 return true;
467 }
468
GetDeviceNumber(const std::string & name,dev_t * dev)469 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
470 struct dm_ioctl io;
471 InitIo(&io, name);
472 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
473 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
474 return false;
475 }
476 *dev = io.dev;
477 return true;
478 }
479
GetDeviceString(const std::string & name,std::string * dev)480 bool DeviceMapper::GetDeviceString(const std::string& name, std::string* dev) {
481 dev_t num;
482 if (!GetDeviceNumber(name, &num)) {
483 return false;
484 }
485 *dev = std::to_string(major(num)) + ":" + std::to_string(minor(num));
486 return true;
487 }
488
GetTableStatus(const std::string & name,std::vector<TargetInfo> * table)489 bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
490 return GetTable(name, 0, table);
491 }
492
GetTableInfo(const std::string & name,std::vector<TargetInfo> * table)493 bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
494 return GetTable(name, DM_STATUS_TABLE_FLAG, table);
495 }
496
497 // private methods of DeviceMapper
GetTable(const std::string & name,uint32_t flags,std::vector<TargetInfo> * table)498 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
499 std::vector<TargetInfo>* table) {
500 std::vector<char> buffer;
501 struct dm_ioctl* io = nullptr;
502
503 for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
504 io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
505
506 InitIo(io, name);
507 io->data_size = buffer.size();
508 io->data_start = sizeof(*io);
509 io->flags = flags;
510 if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
511 PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
512 return false;
513 }
514 if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
515 }
516
517 uint32_t cursor = io->data_start;
518 uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
519 for (uint32_t i = 0; i < io->target_count; i++) {
520 if (cursor + sizeof(struct dm_target_spec) > data_end) {
521 break;
522 }
523 // After each dm_target_spec is a status string. spec->next is an
524 // offset from |io->data_start|, and we clamp it to the size of our
525 // buffer.
526 struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
527 uint32_t data_offset = cursor + sizeof(dm_target_spec);
528 uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
529
530 std::string data;
531 if (next_cursor > data_offset) {
532 // Note: we use c_str() to eliminate any extra trailing 0s.
533 data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
534 }
535 table->emplace_back(*spec, data);
536 cursor = next_cursor;
537 }
538 return true;
539 }
540
InitIo(struct dm_ioctl * io,const std::string & name) const541 void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
542 CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
543 memset(io, 0, sizeof(*io));
544
545 io->version[0] = DM_VERSION0;
546 io->version[1] = DM_VERSION1;
547 io->version[2] = DM_VERSION2;
548 io->data_size = sizeof(*io);
549 io->data_start = 0;
550 if (!name.empty()) {
551 snprintf(io->name, sizeof(io->name), "%s", name.c_str());
552 }
553 }
554
GetTargetType(const struct dm_target_spec & spec)555 std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
556 if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
557 ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
558 return std::string{spec.target_type, static_cast<size_t>(length)};
559 }
560 return std::string{spec.target_type, sizeof(spec.target_type)};
561 }
562
ExtractBlockDeviceName(const std::string & path,std::string * name)563 static bool ExtractBlockDeviceName(const std::string& path, std::string* name) {
564 static constexpr std::string_view kDevBlockPrefix("/dev/block/");
565 if (android::base::StartsWith(path, kDevBlockPrefix)) {
566 *name = path.substr(kDevBlockPrefix.length());
567 return true;
568 }
569 return false;
570 }
571
IsDmBlockDevice(const std::string & path)572 bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
573 std::string name;
574 if (!ExtractBlockDeviceName(path, &name)) {
575 return false;
576 }
577 return android::base::StartsWith(name, "dm-");
578 }
579
GetDmDeviceNameByPath(const std::string & path)580 std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
581 std::string name;
582 if (!ExtractBlockDeviceName(path, &name)) {
583 LOG(WARNING) << path << " is not a block device";
584 return std::nullopt;
585 }
586 if (!android::base::StartsWith(name, "dm-")) {
587 LOG(WARNING) << path << " is not a dm device";
588 return std::nullopt;
589 }
590 std::string dm_name_file = "/sys/block/" + name + "/dm/name";
591 std::string dm_name;
592 if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
593 PLOG(ERROR) << "Failed to read file " << dm_name_file;
594 return std::nullopt;
595 }
596 dm_name = android::base::Trim(dm_name);
597 return dm_name;
598 }
599
GetParentBlockDeviceByPath(const std::string & path)600 std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
601 std::string name;
602 if (!ExtractBlockDeviceName(path, &name)) {
603 LOG(WARNING) << path << " is not a block device";
604 return std::nullopt;
605 }
606 if (!android::base::StartsWith(name, "dm-")) {
607 // Reached bottom of the device mapper stack.
608 return std::nullopt;
609 }
610 auto slaves_dir = "/sys/block/" + name + "/slaves";
611 auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
612 if (dir == nullptr) {
613 PLOG(ERROR) << "Failed to open: " << slaves_dir;
614 return std::nullopt;
615 }
616 std::string sub_device_name = "";
617 for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
618 if (entry->d_type != DT_LNK) continue;
619 if (!sub_device_name.empty()) {
620 LOG(ERROR) << "Too many slaves in " << slaves_dir;
621 return std::nullopt;
622 }
623 sub_device_name = entry->d_name;
624 }
625 if (sub_device_name.empty()) {
626 LOG(ERROR) << "No slaves in " << slaves_dir;
627 return std::nullopt;
628 }
629 return "/dev/block/" + sub_device_name;
630 }
631
IsOverflowSnapshot() const632 bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
633 return spec.target_type == "snapshot"s && data == "Overflow"s;
634 }
635
636 } // namespace dm
637 } // namespace android
638