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