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
CreateEmptyDevice(const std::string & name)173 bool DeviceMapper::CreateEmptyDevice(const std::string& name) {
174 std::string uuid = GenerateUuid();
175 return CreateDevice(name, uuid);
176 }
177
WaitForDevice(const std::string & name,const std::chrono::milliseconds & timeout_ms,std::string * path)178 bool DeviceMapper::WaitForDevice(const std::string& name,
179 const std::chrono::milliseconds& timeout_ms, std::string* path) {
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 (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) {
185 DeleteDevice(name);
186 return false;
187 }
188
189 if (timeout_ms <= std::chrono::milliseconds::zero()) {
190 return true;
191 }
192
193 if (IsRecovery()) {
194 bool non_ab_device = android::base::GetProperty("ro.build.ab_update", "").empty();
195 int sdk = android::base::GetIntProperty("ro.build.version.sdk", 0);
196 if (non_ab_device && sdk && sdk <= 29) {
197 LOG(INFO) << "Detected ueventd incompatibility, reverting to legacy libdm behavior.";
198 unique_path = *path;
199 }
200 }
201
202 if (!WaitForFile(unique_path, timeout_ms)) {
203 LOG(ERROR) << "Failed waiting for device path: " << unique_path;
204 DeleteDevice(name);
205 return false;
206 }
207 return true;
208 }
209
CreateDevice(const std::string & name,const DmTable & table,std::string * path,const std::chrono::milliseconds & timeout_ms)210 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path,
211 const std::chrono::milliseconds& timeout_ms) {
212 if (!CreateEmptyDevice(name)) {
213 return false;
214 }
215
216 if (!LoadTableAndActivate(name, table)) {
217 DeleteDevice(name);
218 return false;
219 }
220
221 if (!WaitForDevice(name, timeout_ms, path)) {
222 DeleteDevice(name);
223 return false;
224 }
225
226 return true;
227 }
228
GetDeviceUniquePath(const std::string & name,std::string * path)229 bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) {
230 struct dm_ioctl io;
231 InitIo(&io, name);
232 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
233 PLOG(ERROR) << "Failed to get device path: " << name;
234 return false;
235 }
236
237 if (io.uuid[0] == '\0') {
238 LOG(ERROR) << "Device does not have a unique path: " << name;
239 return false;
240 }
241 *path = "/dev/block/mapper/by-uuid/"s + io.uuid;
242 return true;
243 }
244
GetDetailedInfo(const std::string & name) const245 std::optional<DeviceMapper::Info> DeviceMapper::GetDetailedInfo(const std::string& name) const {
246 struct dm_ioctl io;
247 InitIo(&io, name);
248 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
249 return std::nullopt;
250 }
251 return Info(io.flags);
252 }
253
GetState(const std::string & name) const254 DmDeviceState DeviceMapper::GetState(const std::string& name) const {
255 struct dm_ioctl io;
256 InitIo(&io, name);
257 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
258 return DmDeviceState::INVALID;
259 }
260 if ((io.flags & DM_ACTIVE_PRESENT_FLAG) && !(io.flags & DM_SUSPEND_FLAG)) {
261 return DmDeviceState::ACTIVE;
262 }
263 return DmDeviceState::SUSPENDED;
264 }
265
ChangeState(const std::string & name,DmDeviceState state)266 bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) {
267 if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) {
268 return false;
269 }
270
271 struct dm_ioctl io;
272 InitIo(&io, name);
273
274 if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG;
275
276 if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) {
277 PLOG(ERROR) << "DM_DEV_SUSPEND "
278 << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed";
279 return false;
280 }
281 return true;
282 }
283
CreateDevice(const std::string & name,const DmTable & table)284 bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) {
285 std::string ignore_path;
286 if (!CreateDevice(name, table, &ignore_path, 0ms)) {
287 return false;
288 }
289 return true;
290 }
291
LoadTableAndActivate(const std::string & name,const DmTable & table)292 bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable& table) {
293 std::string ioctl_buffer(sizeof(struct dm_ioctl), 0);
294 ioctl_buffer += table.Serialize();
295
296 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]);
297 InitIo(io, name);
298 io->data_size = ioctl_buffer.size();
299 io->data_start = sizeof(struct dm_ioctl);
300 io->target_count = static_cast<uint32_t>(table.num_targets());
301 if (table.readonly()) {
302 io->flags |= DM_READONLY_FLAG;
303 }
304 if (ioctl(fd_, DM_TABLE_LOAD, io)) {
305 PLOG(ERROR) << "DM_TABLE_LOAD failed";
306 return false;
307 }
308
309 InitIo(io, name);
310 if (ioctl(fd_, DM_DEV_SUSPEND, io)) {
311 PLOG(ERROR) << "DM_TABLE_SUSPEND resume failed";
312 return false;
313 }
314 return true;
315 }
316
317 // Reads all the available device mapper targets and their corresponding
318 // versions from the kernel and returns in a vector
GetAvailableTargets(std::vector<DmTargetTypeInfo> * targets)319 bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
320 targets->clear();
321
322 // calculate the space needed to read a maximum of kMaxPossibleDmTargets
323 uint32_t payload_size = sizeof(struct dm_target_versions);
324 payload_size += DM_MAX_TYPE_NAME;
325 // device mapper wants every target spec to be aligned at 8-byte boundary
326 payload_size = DM_ALIGN(payload_size);
327 payload_size *= kMaxPossibleDmTargets;
328
329 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
330 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
331 if (buffer == nullptr) {
332 LOG(ERROR) << "failed to allocate memory";
333 return false;
334 }
335
336 // Sets appropriate data size and data_start to make sure we tell kernel
337 // about the total size of the buffer we are passing and where to start
338 // writing the list of targets.
339 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
340 InitIo(io);
341 io->data_size = data_size;
342 io->data_start = sizeof(*io);
343
344 if (ioctl(fd_, DM_LIST_VERSIONS, io)) {
345 PLOG(ERROR) << "DM_LIST_VERSIONS failed";
346 return false;
347 }
348
349 // If the provided buffer wasn't enough to list all targets, note that
350 // any data beyond sizeof(*io) must not be read in this case
351 if (io->flags & DM_BUFFER_FULL_FLAG) {
352 LOG(INFO) << data_size << " is not enough memory to list all dm targets";
353 return false;
354 }
355
356 // if there are no targets registered, return success with empty vector
357 if (io->data_size == sizeof(*io)) {
358 return true;
359 }
360
361 // Parse each target and list the name and version
362 // TODO(b/110035986): Templatize this
363 uint32_t next = sizeof(*io);
364 data_size = io->data_size - next;
365 struct dm_target_versions* vers =
366 reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
367 while (next && data_size) {
368 targets->emplace_back(vers);
369 if (vers->next == 0) {
370 break;
371 }
372 next += vers->next;
373 data_size -= vers->next;
374 vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
375 next);
376 }
377
378 return true;
379 }
380
GetTargetByName(const std::string & name,DmTargetTypeInfo * info)381 bool DeviceMapper::GetTargetByName(const std::string& name, DmTargetTypeInfo* info) {
382 std::vector<DmTargetTypeInfo> targets;
383 if (!GetAvailableTargets(&targets)) {
384 return false;
385 }
386 for (const auto& target : targets) {
387 if (target.name() == name) {
388 if (info) *info = target;
389 return true;
390 }
391 }
392 return false;
393 }
394
GetAvailableDevices(std::vector<DmBlockDevice> * devices)395 bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
396 devices->clear();
397
398 // calculate the space needed to read a maximum of 256 targets, each with
399 // name with maximum length of 16 bytes
400 uint32_t payload_size = sizeof(struct dm_name_list);
401 // 128-bytes for the name
402 payload_size += DM_NAME_LEN;
403 // dm wants every device spec to be aligned at 8-byte boundary
404 payload_size = DM_ALIGN(payload_size);
405 payload_size *= kMaxPossibleDmDevices;
406 uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
407 auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
408 if (buffer == nullptr) {
409 LOG(ERROR) << "failed to allocate memory";
410 return false;
411 }
412
413 // Sets appropriate data size and data_start to make sure we tell kernel
414 // about the total size of the buffer we are passing and where to start
415 // writing the list of targets.
416 struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
417 InitIo(io);
418 io->data_size = data_size;
419 io->data_start = sizeof(*io);
420
421 if (ioctl(fd_, DM_LIST_DEVICES, io)) {
422 PLOG(ERROR) << "DM_LIST_DEVICES failed";
423 return false;
424 }
425
426 // If the provided buffer wasn't enough to list all devices any data
427 // beyond sizeof(*io) must not be read.
428 if (io->flags & DM_BUFFER_FULL_FLAG) {
429 LOG(INFO) << data_size << " is not enough memory to list all dm devices";
430 return false;
431 }
432
433 // if there are no devices created yet, return success with empty vector
434 if (io->data_size == sizeof(*io)) {
435 return true;
436 }
437
438 // Parse each device and add a new DmBlockDevice to the vector
439 // created from the kernel data.
440 uint32_t next = sizeof(*io);
441 data_size = io->data_size - next;
442 struct dm_name_list* dm_dev =
443 reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
444
445 while (next && data_size) {
446 devices->emplace_back((dm_dev));
447 if (dm_dev->next == 0) {
448 break;
449 }
450 next += dm_dev->next;
451 data_size -= dm_dev->next;
452 dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
453 }
454
455 return true;
456 }
457
458 // Accepts a device mapper device name (like system_a, vendor_b etc) and
459 // returns the path to it's device node (or symlink to the device node)
GetDmDevicePathByName(const std::string & name,std::string * path)460 bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* path) {
461 struct dm_ioctl io;
462 InitIo(&io, name);
463 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
464 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
465 return false;
466 }
467
468 uint32_t dev_num = minor(io.dev);
469 *path = "/dev/block/dm-" + std::to_string(dev_num);
470 return true;
471 }
472
473 // Accepts a device mapper device name (like system_a, vendor_b etc) and
474 // returns its UUID.
GetDmDeviceUuidByName(const std::string & name,std::string * uuid)475 bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
476 struct dm_ioctl io;
477 InitIo(&io, name);
478 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
479 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
480 return false;
481 }
482
483 *uuid = std::string(io.uuid);
484 return true;
485 }
486
GetDeviceNumber(const std::string & name,dev_t * dev)487 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
488 struct dm_ioctl io;
489 InitIo(&io, name);
490 if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
491 PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
492 return false;
493 }
494 *dev = io.dev;
495 return true;
496 }
497
GetDeviceString(const std::string & name,std::string * dev)498 bool DeviceMapper::GetDeviceString(const std::string& name, std::string* dev) {
499 dev_t num;
500 if (!GetDeviceNumber(name, &num)) {
501 return false;
502 }
503 *dev = std::to_string(major(num)) + ":" + std::to_string(minor(num));
504 return true;
505 }
506
GetTableStatus(const std::string & name,std::vector<TargetInfo> * table)507 bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
508 return GetTable(name, 0, table);
509 }
510
GetTableInfo(const std::string & name,std::vector<TargetInfo> * table)511 bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
512 return GetTable(name, DM_STATUS_TABLE_FLAG, table);
513 }
514
515 // private methods of DeviceMapper
GetTable(const std::string & name,uint32_t flags,std::vector<TargetInfo> * table)516 bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
517 std::vector<TargetInfo>* table) {
518 std::vector<char> buffer;
519 struct dm_ioctl* io = nullptr;
520
521 for (buffer.resize(4096);; buffer.resize(buffer.size() * 2)) {
522 io = reinterpret_cast<struct dm_ioctl*>(&buffer[0]);
523
524 InitIo(io, name);
525 io->data_size = buffer.size();
526 io->data_start = sizeof(*io);
527 io->flags = flags;
528 if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
529 PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
530 return false;
531 }
532 if (!(io->flags & DM_BUFFER_FULL_FLAG)) break;
533 }
534
535 uint32_t cursor = io->data_start;
536 uint32_t data_end = std::min(io->data_size, uint32_t(buffer.size()));
537 for (uint32_t i = 0; i < io->target_count; i++) {
538 if (cursor + sizeof(struct dm_target_spec) > data_end) {
539 break;
540 }
541 // After each dm_target_spec is a status string. spec->next is an
542 // offset from |io->data_start|, and we clamp it to the size of our
543 // buffer.
544 struct dm_target_spec* spec = reinterpret_cast<struct dm_target_spec*>(&buffer[cursor]);
545 uint32_t data_offset = cursor + sizeof(dm_target_spec);
546 uint32_t next_cursor = std::min(io->data_start + spec->next, data_end);
547
548 std::string data;
549 if (next_cursor > data_offset) {
550 // Note: we use c_str() to eliminate any extra trailing 0s.
551 data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str();
552 }
553 table->emplace_back(*spec, data);
554 cursor = next_cursor;
555 }
556 return true;
557 }
558
InitIo(struct dm_ioctl * io,const std::string & name) const559 void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const {
560 CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization";
561 memset(io, 0, sizeof(*io));
562
563 io->version[0] = DM_VERSION0;
564 io->version[1] = DM_VERSION1;
565 io->version[2] = DM_VERSION2;
566 io->data_size = sizeof(*io);
567 io->data_start = 0;
568 if (!name.empty()) {
569 snprintf(io->name, sizeof(io->name), "%s", name.c_str());
570 }
571 }
572
GetTargetType(const struct dm_target_spec & spec)573 std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) {
574 if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) {
575 ptrdiff_t length = reinterpret_cast<const char*>(p) - spec.target_type;
576 return std::string{spec.target_type, static_cast<size_t>(length)};
577 }
578 return std::string{spec.target_type, sizeof(spec.target_type)};
579 }
580
ExtractBlockDeviceName(const std::string & path)581 std::optional<std::string> ExtractBlockDeviceName(const std::string& path) {
582 static constexpr std::string_view kDevBlockPrefix("/dev/block/");
583 if (android::base::StartsWith(path, kDevBlockPrefix)) {
584 return path.substr(kDevBlockPrefix.length());
585 }
586 return {};
587 }
588
IsDmBlockDevice(const std::string & path)589 bool DeviceMapper::IsDmBlockDevice(const std::string& path) {
590 std::optional<std::string> name = ExtractBlockDeviceName(path);
591 return name && android::base::StartsWith(*name, "dm-");
592 }
593
GetDmDeviceNameByPath(const std::string & path)594 std::optional<std::string> DeviceMapper::GetDmDeviceNameByPath(const std::string& path) {
595 std::optional<std::string> name = ExtractBlockDeviceName(path);
596 if (!name) {
597 LOG(WARNING) << path << " is not a block device";
598 return std::nullopt;
599 }
600 if (!android::base::StartsWith(*name, "dm-")) {
601 LOG(WARNING) << path << " is not a dm device";
602 return std::nullopt;
603 }
604 std::string dm_name_file = "/sys/block/" + *name + "/dm/name";
605 std::string dm_name;
606 if (!android::base::ReadFileToString(dm_name_file, &dm_name)) {
607 PLOG(ERROR) << "Failed to read file " << dm_name_file;
608 return std::nullopt;
609 }
610 dm_name = android::base::Trim(dm_name);
611 return dm_name;
612 }
613
GetParentBlockDeviceByPath(const std::string & path)614 std::optional<std::string> DeviceMapper::GetParentBlockDeviceByPath(const std::string& path) {
615 std::optional<std::string> name = ExtractBlockDeviceName(path);
616 if (!name) {
617 LOG(WARNING) << path << " is not a block device";
618 return std::nullopt;
619 }
620 if (!android::base::StartsWith(*name, "dm-")) {
621 // Reached bottom of the device mapper stack.
622 return std::nullopt;
623 }
624 auto slaves_dir = "/sys/block/" + *name + "/slaves";
625 auto dir = std::unique_ptr<DIR, decltype(&closedir)>(opendir(slaves_dir.c_str()), closedir);
626 if (dir == nullptr) {
627 PLOG(ERROR) << "Failed to open: " << slaves_dir;
628 return std::nullopt;
629 }
630 std::string sub_device_name = "";
631 for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) {
632 if (entry->d_type != DT_LNK) continue;
633 if (!sub_device_name.empty()) {
634 LOG(ERROR) << "Too many slaves in " << slaves_dir;
635 return std::nullopt;
636 }
637 sub_device_name = entry->d_name;
638 }
639 if (sub_device_name.empty()) {
640 LOG(ERROR) << "No slaves in " << slaves_dir;
641 return std::nullopt;
642 }
643 return "/dev/block/" + sub_device_name;
644 }
645
IsOverflowSnapshot() const646 bool DeviceMapper::TargetInfo::IsOverflowSnapshot() const {
647 return spec.target_type == "snapshot"s && data == "Overflow"s;
648 }
649
650 } // namespace dm
651 } // namespace android
652