blob: f78093bdfcf3d41b1506d8c25025c0707c0e3693 [file] [log] [blame]
Sandeep Patil59f04ee2018-05-30 13:46:55 -07001/*
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 <errno.h>
18#include <fcntl.h>
19#include <getopt.h>
20#include <linux/dm-ioctl.h>
21#include <sys/ioctl.h>
22#include <sys/types.h>
23#include <unistd.h>
24
Yifan Hongd449e2e2018-08-16 09:36:45 -070025#include <android-base/logging.h>
David Andersonbac58ae2018-06-20 16:37:36 -070026#include <android-base/parseint.h>
Sandeep Patil59f04ee2018-05-30 13:46:55 -070027#include <android-base/unique_fd.h>
David Andersonb1a834e2018-06-19 18:24:40 -070028#include <libdm/dm.h>
Sandeep Patil59f04ee2018-05-30 13:46:55 -070029
30#include <functional>
31#include <iomanip>
32#include <ios>
33#include <iostream>
34#include <map>
David Andersonbac58ae2018-06-20 16:37:36 -070035#include <sstream>
Sandeep Patil59f04ee2018-05-30 13:46:55 -070036#include <string>
37#include <vector>
38
39using DeviceMapper = ::android::dm::DeviceMapper;
David Andersone1c07442018-06-19 18:13:07 -070040using DmTable = ::android::dm::DmTable;
Sandeep Patil59f04ee2018-05-30 13:46:55 -070041using DmTarget = ::android::dm::DmTarget;
David Andersonbac58ae2018-06-20 16:37:36 -070042using DmTargetLinear = ::android::dm::DmTargetLinear;
43using DmTargetZero = ::android::dm::DmTargetZero;
Sandeep Patilefc54792018-07-23 15:24:55 -070044using DmTargetAndroidVerity = ::android::dm::DmTargetAndroidVerity;
Paul Lawrence8a9c2942018-08-30 11:09:17 -070045using DmTargetBow = ::android::dm::DmTargetBow;
David Andersonc7def682018-06-20 13:15:31 -070046using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
Sandeep Patilf603cfd2018-06-13 12:09:58 -070047using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
Sandeep Patil59f04ee2018-05-30 13:46:55 -070048
49static int Usage(void) {
Sandeep Patild34d0ef2018-06-13 18:38:07 -070050 std::cerr << "usage: dmctl <command> [command options]" << std::endl;
51 std::cerr << "commands:" << std::endl;
David Andersonbac58ae2018-06-20 16:37:36 -070052 std::cerr << " create <dm-name> [-ro] <targets...>" << std::endl;
Sandeep Patild34d0ef2018-06-13 18:38:07 -070053 std::cerr << " delete <dm-name>" << std::endl;
54 std::cerr << " list <devices | targets>" << std::endl;
David Anderson5e9e74b2018-06-21 14:46:34 -070055 std::cerr << " getpath <dm-name>" << std::endl;
David Anderson40b59482018-06-25 17:55:01 -070056 std::cerr << " table <dm-name>" << std::endl;
Sandeep Patild34d0ef2018-06-13 18:38:07 -070057 std::cerr << " help" << std::endl;
David Andersonbac58ae2018-06-20 16:37:36 -070058 std::cerr << std::endl;
59 std::cerr << "Target syntax:" << std::endl;
60 std::cerr << " <target_type> <start_sector> <num_sectors> [target_data]" << std::endl;
Sandeep Patil59f04ee2018-05-30 13:46:55 -070061 return -EINVAL;
62}
63
David Andersonbac58ae2018-06-20 16:37:36 -070064class TargetParser final {
65 public:
66 TargetParser(int argc, char** argv) : arg_index_(0), argc_(argc), argv_(argv) {}
67
68 bool More() const { return arg_index_ < argc_; }
69 std::unique_ptr<DmTarget> Next() {
70 if (!HasArgs(3)) {
71 std::cerr << "Expected <target_type> <start_sector> <num_sectors>" << std::endl;
72 return nullptr;
73 }
74
75 std::string target_type = NextArg();
76 uint64_t start_sector, num_sectors;
77 if (!android::base::ParseUint(NextArg(), &start_sector)) {
78 std::cerr << "Expected start sector, got: " << PreviousArg() << std::endl;
79 return nullptr;
80 }
81 if (!android::base::ParseUint(NextArg(), &num_sectors) || !num_sectors) {
82 std::cerr << "Expected non-zero sector count, got: " << PreviousArg() << std::endl;
83 return nullptr;
84 }
85
86 if (target_type == "zero") {
87 return std::make_unique<DmTargetZero>(start_sector, num_sectors);
88 } else if (target_type == "linear") {
89 if (!HasArgs(2)) {
90 std::cerr << "Expected \"linear\" <block_device> <sector>" << std::endl;
91 return nullptr;
92 }
93
94 std::string block_device = NextArg();
95 uint64_t physical_sector;
96 if (!android::base::ParseUint(NextArg(), &physical_sector)) {
97 std::cerr << "Expected sector, got: \"" << PreviousArg() << "\"" << std::endl;
98 return nullptr;
99 }
100 return std::make_unique<DmTargetLinear>(start_sector, num_sectors, block_device,
101 physical_sector);
Sandeep Patilefc54792018-07-23 15:24:55 -0700102 } else if (target_type == "android-verity") {
103 if (!HasArgs(2)) {
104 std::cerr << "Expected \"android-verity\" <public-key-id> <block_device>"
105 << std::endl;
106 return nullptr;
107 }
108 std::string keyid = NextArg();
109 std::string block_device = NextArg();
110 return std::make_unique<DmTargetAndroidVerity>(start_sector, num_sectors, keyid,
111 block_device);
Paul Lawrence8a9c2942018-08-30 11:09:17 -0700112 } else if (target_type == "bow") {
113 if (!HasArgs(1)) {
114 std::cerr << "Expected \"bow\" <block_device>" << std::endl;
115 return nullptr;
116 }
117 std::string block_device = NextArg();
118 return std::make_unique<DmTargetBow>(start_sector, num_sectors, block_device);
David Andersonbac58ae2018-06-20 16:37:36 -0700119 } else {
120 std::cerr << "Unrecognized target type: " << target_type << std::endl;
121 return nullptr;
122 }
123 }
124
125 private:
126 bool HasArgs(int count) { return arg_index_ + count <= argc_; }
127 const char* NextArg() {
128 CHECK(arg_index_ < argc_);
129 return argv_[arg_index_++];
130 }
131 const char* PreviousArg() {
132 CHECK(arg_index_ >= 0);
133 return argv_[arg_index_ - 1];
134 }
135
136 private:
137 int arg_index_;
138 int argc_;
139 char** argv_;
140};
141
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700142static int DmCreateCmdHandler(int argc, char** argv) {
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700143 if (argc < 1) {
David Andersonbac58ae2018-06-20 16:37:36 -0700144 std::cerr << "Usage: dmctl create <dm-name> [-ro] <targets...>" << std::endl;
145 return -EINVAL;
146 }
147 std::string name = argv[0];
148
149 // Parse extended options first.
150 DmTable table;
151 int arg_index = 1;
152 while (arg_index < argc && argv[arg_index][0] == '-') {
153 if (strcmp(argv[arg_index], "-ro") == 0) {
154 table.set_readonly(true);
Sandeep Patil0d469de2018-07-23 14:50:26 -0700155 arg_index++;
David Andersonbac58ae2018-06-20 16:37:36 -0700156 } else {
157 std::cerr << "Unrecognized option: " << argv[arg_index] << std::endl;
158 return -EINVAL;
159 }
David Andersonbac58ae2018-06-20 16:37:36 -0700160 }
161
162 // Parse everything else as target information.
163 TargetParser parser(argc - arg_index, argv + arg_index);
164 while (parser.More()) {
165 std::unique_ptr<DmTarget> target = parser.Next();
166 if (!target || !table.AddTarget(std::move(target))) {
167 return -EINVAL;
168 }
169 }
170
171 if (table.num_targets() == 0) {
172 std::cerr << "Must define at least one target." << std::endl;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700173 return -EINVAL;
174 }
175
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700176 DeviceMapper& dm = DeviceMapper::Instance();
David Andersone1c07442018-06-19 18:13:07 -0700177 if (!dm.CreateDevice(name, table)) {
David Andersonb6181e32018-06-19 15:37:25 -0700178 std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700179 return -EIO;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700180 }
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700181 return 0;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700182}
183
184static int DmDeleteCmdHandler(int argc, char** argv) {
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700185 if (argc < 1) {
David Andersonb6181e32018-06-19 15:37:25 -0700186 std::cerr << "Usage: dmctl delete <name>" << std::endl;
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700187 return -EINVAL;
188 }
189
190 std::string name = argv[0];
191 DeviceMapper& dm = DeviceMapper::Instance();
192 if (!dm.DeleteDevice(name)) {
David Andersonb6181e32018-06-19 15:37:25 -0700193 std::cerr << "Failed to delete [" << name << "]" << std::endl;
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700194 return -EIO;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700195 }
196
197 return 0;
198}
199
Sandeep Patilf603cfd2018-06-13 12:09:58 -0700200static int DmListTargets(DeviceMapper& dm) {
David Andersonc7def682018-06-20 13:15:31 -0700201 std::vector<DmTargetTypeInfo> targets;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700202 if (!dm.GetAvailableTargets(&targets)) {
Sandeep Patil45d94ab2018-06-12 17:03:56 -0700203 std::cerr << "Failed to read available device mapper targets" << std::endl;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700204 return -errno;
205 }
206
Sandeep Patilf603cfd2018-06-13 12:09:58 -0700207 std::cout << "Available Device Mapper Targets:" << std::endl;
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700208 if (targets.empty()) {
209 std::cout << " <empty>" << std::endl;
210 return 0;
211 }
212
213 for (const auto& target : targets) {
214 std::cout << std::left << std::setw(20) << target.name() << " : " << target.version()
215 << std::endl;
216 }
217
218 return 0;
219}
220
Sandeep Patilf603cfd2018-06-13 12:09:58 -0700221static int DmListDevices(DeviceMapper& dm) {
222 std::vector<DmBlockDevice> devices;
223 if (!dm.GetAvailableDevices(&devices)) {
224 std::cerr << "Failed to read available device mapper devices" << std::endl;
225 return -errno;
226 }
227 std::cout << "Available Device Mapper Devices:" << std::endl;
228 if (devices.empty()) {
229 std::cout << " <empty>" << std::endl;
230 return 0;
231 }
232
233 for (const auto& dev : devices) {
234 std::cout << std::left << std::setw(20) << dev.name() << " : " << dev.Major() << ":"
235 << dev.Minor() << std::endl;
236 }
237
238 return 0;
239}
240
241static const std::map<std::string, std::function<int(DeviceMapper&)>> listmap = {
242 {"targets", DmListTargets},
243 {"devices", DmListDevices},
244};
245
246static int DmListCmdHandler(int argc, char** argv) {
247 if (argc < 1) {
248 std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
249 return -EINVAL;
250 }
251
252 DeviceMapper& dm = DeviceMapper::Instance();
253 for (const auto& l : listmap) {
254 if (l.first == argv[0]) return l.second(dm);
255 }
256
257 std::cerr << "Invalid argument to \'dmctl list\': " << argv[0] << std::endl;
258 return -EINVAL;
259}
260
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700261static int HelpCmdHandler(int /* argc */, char** /* argv */) {
262 Usage();
263 return 0;
264}
265
David Anderson5e9e74b2018-06-21 14:46:34 -0700266static int GetPathCmdHandler(int argc, char** argv) {
267 if (argc != 1) {
268 std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
269 return -EINVAL;
270 }
271
272 DeviceMapper& dm = DeviceMapper::Instance();
273 std::string path;
274 if (!dm.GetDmDevicePathByName(argv[0], &path)) {
275 std::cerr << "Could not query path of device \"" << argv[0] << "\"." << std::endl;
276 return -EINVAL;
277 }
278 std::cout << path << std::endl;
279 return 0;
280}
281
David Anderson40b59482018-06-25 17:55:01 -0700282static int TableCmdHandler(int argc, char** argv) {
283 if (argc != 1) {
284 std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
285 return -EINVAL;
286 }
287
288 DeviceMapper& dm = DeviceMapper::Instance();
289 std::vector<DeviceMapper::TargetInfo> table;
290 if (!dm.GetTableStatus(argv[0], &table)) {
291 std::cerr << "Could not query table status of device \"" << argv[0] << "\"." << std::endl;
292 return -EINVAL;
293 }
294 std::cout << "Targets in the device-mapper table for " << argv[0] << ":" << std::endl;
295 for (const auto& target : table) {
296 std::cout << target.spec.sector_start << "-"
297 << (target.spec.sector_start + target.spec.length) << ": "
298 << target.spec.target_type;
299 if (!target.data.empty()) {
300 std::cout << ", " << target.data;
301 }
302 std::cout << std::endl;
303 }
304 return 0;
305}
306
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700307static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
David Anderson5e9e74b2018-06-21 14:46:34 -0700308 // clang-format off
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700309 {"create", DmCreateCmdHandler},
310 {"delete", DmDeleteCmdHandler},
311 {"list", DmListCmdHandler},
312 {"help", HelpCmdHandler},
David Anderson5e9e74b2018-06-21 14:46:34 -0700313 {"getpath", GetPathCmdHandler},
David Anderson40b59482018-06-25 17:55:01 -0700314 {"table", TableCmdHandler},
David Anderson5e9e74b2018-06-21 14:46:34 -0700315 // clang-format on
Sandeep Patil59f04ee2018-05-30 13:46:55 -0700316};
317
318int main(int argc, char** argv) {
319 android::base::InitLogging(argv, &android::base::StderrLogger);
320 if (argc < 2) {
321 return Usage();
322 }
323
324 for (const auto& cmd : cmdmap) {
325 if (cmd.first == argv[1]) {
326 return cmd.second(argc - 2, argv + 2);
327 }
328 }
329
330 return Usage();
331}