1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd/ArgumentTypes.h"
5 #include "tools/rbd/Shell.h"
6 #include "tools/rbd/Utils.h"
7 #include "include/stringify.h"
8 #include "common/SubProcess.h"
10 #include <boost/algorithm/string.hpp>
11 #include <boost/algorithm/string/predicate.hpp>
12 #include <boost/program_options.hpp>
18 namespace at
= argument_types
;
19 namespace po
= boost::program_options
;
21 static int call_nbd_cmd(const po::variables_map
&vm
,
22 const std::vector
<std::string
> &args
,
23 const std::vector
<std::string
> &ceph_global_init_args
) {
24 #if defined(__FreeBSD__) || defined(_WIN32)
25 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
28 char exe_path
[PATH_MAX
];
29 ssize_t exe_path_bytes
= readlink("/proc/self/exe", exe_path
,
30 sizeof(exe_path
) - 1);
31 if (exe_path_bytes
< 0) {
32 strcpy(exe_path
, "rbd-nbd");
34 if (snprintf(exe_path
+ exe_path_bytes
,
35 sizeof(exe_path
) - exe_path_bytes
,
41 SubProcess
process(exe_path
, SubProcess::KEEP
, SubProcess::KEEP
, SubProcess::KEEP
);
43 for (auto &arg
: ceph_global_init_args
) {
44 process
.add_cmd_arg(arg
.c_str());
47 for (auto &arg
: args
) {
48 process
.add_cmd_arg(arg
.c_str());
51 if (process
.spawn()) {
52 std::cerr
<< "rbd: failed to run rbd-nbd: " << process
.err() << std::endl
;
54 } else if (process
.join()) {
55 std::cerr
<< "rbd: rbd-nbd failed with error: " << process
.err() << std::endl
;
63 int execute_list(const po::variables_map
&vm
,
64 const std::vector
<std::string
> &ceph_global_init_args
) {
65 #if defined(__FreeBSD__) || defined(_WIN32)
66 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
69 std::vector
<std::string
> args
;
71 args
.push_back("list-mapped");
73 if (vm
.count("format")) {
74 args
.push_back("--format");
75 args
.push_back(vm
["format"].as
<at::Format
>().value
);
77 if (vm
["pretty-format"].as
<bool>()) {
78 args
.push_back("--pretty-format");
81 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
85 int execute_attach(const po::variables_map
&vm
,
86 const std::vector
<std::string
> &ceph_global_init_args
) {
87 #if defined(__FreeBSD__) || defined(_WIN32)
88 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
91 std::vector
<std::string
> args
;
92 std::string device_path
;
94 args
.push_back("attach");
96 int r
= utils::get_image_or_snap_spec(vm
, &img
);
102 if (vm
.count("device")) {
103 device_path
= vm
["device"].as
<std::string
>();
104 args
.push_back("--device");
105 args
.push_back(device_path
);
107 std::cerr
<< "rbd: device was not specified" << std::endl
;
111 if (vm
["show-cookie"].as
<bool>()) {
112 args
.push_back("--show-cookie");
115 if (vm
.count("cookie")) {
116 args
.push_back("--cookie");
117 args
.push_back(vm
["cookie"].as
<std::string
>());
118 } else if (!vm
["force"].as
<bool>()) {
119 std::cerr
<< "rbd: could not validate attach request\n";
120 std::cerr
<< "rbd: mismatching the image and the device may lead to data corruption\n";
121 std::cerr
<< "rbd: must specify --cookie <arg> or --force to proceed" << std::endl
;
125 if (vm
.count(at::SNAPSHOT_ID
)) {
126 args
.push_back("--snap-id");
127 args
.push_back(std::to_string(vm
[at::SNAPSHOT_ID
].as
<uint64_t>()));
130 if (vm
["quiesce"].as
<bool>()) {
131 args
.push_back("--quiesce");
134 if (vm
["read-only"].as
<bool>()) {
135 args
.push_back("--read-only");
138 if (vm
["exclusive"].as
<bool>()) {
139 args
.push_back("--exclusive");
142 if (vm
.count("quiesce-hook")) {
143 args
.push_back("--quiesce-hook");
144 args
.push_back(vm
["quiesce-hook"].as
<std::string
>());
147 if (vm
.count("options")) {
148 utils::append_options_as_args(vm
["options"].as
<std::vector
<std::string
>>(),
152 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
156 int execute_detach(const po::variables_map
&vm
,
157 const std::vector
<std::string
> &ceph_global_init_args
) {
158 #if defined(__FreeBSD__) || defined(_WIN32)
159 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
162 std::string device_name
= utils::get_positional_argument(vm
, 0);
163 if (!boost::starts_with(device_name
, "/dev/")) {
167 std::vector
<std::string
> args
;
169 args
.push_back("detach");
170 std::string image_name
;
171 if (device_name
.empty()) {
172 int r
= utils::get_image_or_snap_spec(vm
, &image_name
);
177 if (image_name
.empty()) {
178 std::cerr
<< "rbd: detach requires either image name or device path"
183 if (vm
.count(at::SNAPSHOT_ID
)) {
184 args
.push_back("--snap-id");
185 args
.push_back(std::to_string(vm
[at::SNAPSHOT_ID
].as
<uint64_t>()));
189 args
.push_back(device_name
.empty() ? image_name
: device_name
);
191 if (vm
.count("options")) {
192 utils::append_options_as_args(vm
["options"].as
<std::vector
<std::string
>>(),
196 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
200 int execute_map(const po::variables_map
&vm
,
201 const std::vector
<std::string
> &ceph_global_init_args
) {
202 #if defined(__FreeBSD__) || defined(_WIN32)
203 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
206 std::vector
<std::string
> args
;
208 args
.push_back("map");
210 int r
= utils::get_image_or_snap_spec(vm
, &img
);
216 if (vm
["quiesce"].as
<bool>()) {
217 args
.push_back("--quiesce");
220 if (vm
["show-cookie"].as
<bool>()) {
221 args
.push_back("--show-cookie");
224 if (vm
.count("cookie")) {
225 args
.push_back("--cookie");
226 args
.push_back(vm
["cookie"].as
<std::string
>());
229 if (vm
.count(at::SNAPSHOT_ID
)) {
230 args
.push_back("--snap-id");
231 args
.push_back(std::to_string(vm
[at::SNAPSHOT_ID
].as
<uint64_t>()));
234 if (vm
["read-only"].as
<bool>()) {
235 args
.push_back("--read-only");
238 if (vm
["exclusive"].as
<bool>()) {
239 args
.push_back("--exclusive");
242 if (vm
.count("quiesce-hook")) {
243 args
.push_back("--quiesce-hook");
244 args
.push_back(vm
["quiesce-hook"].as
<std::string
>());
247 if (vm
.count("options")) {
248 utils::append_options_as_args(vm
["options"].as
<std::vector
<std::string
>>(),
252 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
256 int execute_unmap(const po::variables_map
&vm
,
257 const std::vector
<std::string
> &ceph_global_init_args
) {
258 #if defined(__FreeBSD__) || defined(_WIN32)
259 std::cerr
<< "rbd: nbd device is not supported" << std::endl
;
262 std::string device_name
= utils::get_positional_argument(vm
, 0);
263 if (!boost::starts_with(device_name
, "/dev/")) {
267 std::vector
<std::string
> args
;
269 args
.push_back("unmap");
270 std::string image_name
;
271 if (device_name
.empty()) {
272 int r
= utils::get_image_or_snap_spec(vm
, &image_name
);
277 if (image_name
.empty()) {
278 std::cerr
<< "rbd: unmap requires either image name or device path"
283 if (vm
.count(at::SNAPSHOT_ID
)) {
284 args
.push_back("--snap-id");
285 args
.push_back(std::to_string(vm
[at::SNAPSHOT_ID
].as
<uint64_t>()));
289 args
.push_back(device_name
.empty() ? image_name
: device_name
);
291 if (vm
.count("options")) {
292 utils::append_options_as_args(vm
["options"].as
<std::vector
<std::string
>>(),
296 return call_nbd_cmd(vm
, args
, ceph_global_init_args
);
300 void get_list_arguments_deprecated(po::options_description
*positional
,
301 po::options_description
*options
) {
302 at::add_format_options(options
);
305 int execute_list_deprecated(const po::variables_map
&vm
,
306 const std::vector
<std::string
> &ceph_global_args
) {
307 std::cerr
<< "rbd: 'nbd list' command is deprecated, "
308 << "use 'device list -t nbd' instead" << std::endl
;
309 return execute_list(vm
, ceph_global_args
);
312 void get_map_arguments_deprecated(po::options_description
*positional
,
313 po::options_description
*options
) {
314 at::add_image_or_snap_spec_options(positional
, options
,
315 at::ARGUMENT_MODIFIER_NONE
);
316 options
->add_options()
317 ("read-only", po::bool_switch(), "map read-only")
318 ("exclusive", po::bool_switch(), "forbid writes by other clients")
319 ("device", po::value
<std::string
>(), "specify nbd device")
320 ("nbds_max", po::value
<std::string
>(), "override module param nbds_max")
321 ("max_part", po::value
<std::string
>(), "override module param max_part")
322 ("timeout", po::value
<std::string
>(), "set nbd request timeout (seconds)");
325 int execute_map_deprecated(const po::variables_map
&vm_deprecated
,
326 const std::vector
<std::string
> &ceph_global_args
) {
327 std::cerr
<< "rbd: 'nbd map' command is deprecated, "
328 << "use 'device map -t nbd' instead" << std::endl
;
330 po::options_description options
;
331 options
.add_options()
332 ("options,o", po::value
<std::vector
<std::string
>>()
333 ->default_value(std::vector
<std::string
>(), ""), "");
335 po::variables_map vm
= vm_deprecated
;
336 po::store(po::command_line_parser({}).options(options
).run(), vm
);
338 std::vector
<std::string
> opts
;
339 if (vm_deprecated
.count("device")) {
340 opts
.push_back("device=" + vm_deprecated
["device"].as
<std::string
>());
342 if (vm_deprecated
.count("nbds_max")) {
343 opts
.push_back("nbds_max=" + vm_deprecated
["nbds_max"].as
<std::string
>());
345 if (vm_deprecated
.count("max_part")) {
346 opts
.push_back("max_part=" + vm_deprecated
["max_part"].as
<std::string
>());
348 if (vm_deprecated
.count("timeout")) {
349 opts
.push_back("timeout=" + vm_deprecated
["timeout"].as
<std::string
>());
352 vm
.at("options").value() = boost::any(opts
);
354 return execute_map(vm
, ceph_global_args
);
357 void get_unmap_arguments_deprecated(po::options_description
*positional
,
358 po::options_description
*options
) {
359 positional
->add_options()
360 ("image-or-snap-or-device-spec",
361 "image, snapshot, or device specification\n"
362 "[<pool-name>/]<image-name>[@<snap-name>] or <device-path>");
363 at::add_pool_option(options
, at::ARGUMENT_MODIFIER_NONE
);
364 at::add_image_option(options
, at::ARGUMENT_MODIFIER_NONE
);
365 at::add_snap_option(options
, at::ARGUMENT_MODIFIER_NONE
);
368 int execute_unmap_deprecated(const po::variables_map
&vm
,
369 const std::vector
<std::string
> &ceph_global_args
) {
370 std::cerr
<< "rbd: 'nbd unmap' command is deprecated, "
371 << "use 'device unmap -t nbd' instead" << std::endl
;
372 return execute_unmap(vm
, ceph_global_args
);
375 Shell::Action
action_show_deprecated(
376 {"nbd", "list"}, {"nbd", "ls"}, "List the nbd devices already used.", "",
377 &get_list_arguments_deprecated
, &execute_list_deprecated
, false);
379 Shell::Action
action_map_deprecated(
380 {"nbd", "map"}, {}, "Map image to a nbd device.", "",
381 &get_map_arguments_deprecated
, &execute_map_deprecated
, false);
383 Shell::Action
action_unmap_deprecated(
384 {"nbd", "unmap"}, {}, "Unmap a nbd device.", "",
385 &get_unmap_arguments_deprecated
, &execute_unmap_deprecated
, false);
388 } // namespace action