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