1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <brillo/blkdev_utils/device_mapper_task.h>
6 
7 #include <libdevmapper.h>
8 #include <string>
9 #include <utility>
10 
11 #include <brillo/blkdev_utils/device_mapper.h>
12 
13 namespace brillo {
14 
DevmapperTaskImpl(int type)15 DevmapperTaskImpl::DevmapperTaskImpl(int type)
16     : task_(DmTaskPtr(dm_task_create(type), &dm_task_destroy)) {}
17 
SetName(const std::string & name)18 bool DevmapperTaskImpl::SetName(const std::string& name) {
19   if (!task_ || !dm_task_set_name(task_.get(), name.c_str())) {
20     LOG(ERROR) << "SetName failed";
21     return false;
22   }
23   return true;
24 }
25 
AddTarget(uint64_t start,uint64_t length,const std::string & type,const SecureBlob & parameters)26 bool DevmapperTaskImpl::AddTarget(uint64_t start,
27                                   uint64_t length,
28                                   const std::string& type,
29                                   const SecureBlob& parameters) {
30   // Strings stored in SecureBlob don't end with '\0'. Unfortunately,
31   // this causes accesses beyond the allocated storage space if any
32   // of the functions expecting a c-string get passed a SecureBlob.data().
33   // Temporarily, assign to a string.
34   // TODO(sarthakkukreti): Evaluate creation of a SecureCString to keep
35   // string data safe.
36   std::string parameters_str = parameters.to_string();
37   if (!task_ ||
38       !dm_task_add_target(task_.get(), start, length, type.c_str(),
39                           parameters_str.c_str())) {
40     LOG(ERROR) << "AddTarget failed";
41     return false;
42   }
43   // Clear the string.
44   parameters_str.clear();
45   return true;
46 }
47 
GetNextTarget(uint64_t * start,uint64_t * length,std::string * type,SecureBlob * parameters)48 bool DevmapperTaskImpl::GetNextTarget(uint64_t* start,
49                                       uint64_t* length,
50                                       std::string* type,
51                                       SecureBlob* parameters) {
52   if (!task_) {
53     LOG(ERROR) << "GetNextTarget: invalid task.";
54     return false;
55   }
56 
57   char *type_cstr, *parameters_cstr;
58   next_target_ = dm_get_next_target(task_.get(), next_target_, start, length,
59                                     &type_cstr, &parameters_cstr);
60 
61   if (type_cstr)
62     *type = std::string(type_cstr);
63   if (parameters_cstr) {
64     SecureBlob parameters_blob(parameters_cstr);
65     memset(parameters_cstr, 0, parameters_blob.size());
66     *parameters = std::move(parameters_blob);
67   }
68 
69   return (next_target_ != nullptr);
70 }
71 
Run(bool udev_sync)72 bool DevmapperTaskImpl::Run(bool udev_sync) {
73   uint32_t cookie = 0;
74 
75   if (!task_) {
76     LOG(ERROR) << "Invalid task.";
77     return false;
78   }
79 
80   if (udev_sync && !dm_task_set_cookie(task_.get(), &cookie, 0)) {
81     LOG(ERROR) << "dm_task_set_cookie failed";
82     return false;
83   }
84 
85   if (!dm_task_run(task_.get())) {
86     LOG(ERROR) << "dm_task_run failed";
87     return false;
88   }
89 
90   // Make sure the node exists before continuing.
91   // TODO(sarthakkukreti): move to dm_udev_wait_immediate() on uprevving lvm2.
92   return udev_sync ? (dm_udev_wait(cookie) != 0) : true;
93 }
94 
95 }  // namespace brillo
96